Static Analysis: ChecksEffectsInteraction, Constant Function, Inline Assembly. Without integration tests and modifier support
parent
01d700dc7c
commit
11917ffcfb
@ -0,0 +1,93 @@ |
||||
var common = require('./staticAnalysisCommon') |
||||
var AstWalker = require('ethereum-remix').util.AstWalker |
||||
|
||||
function abstractAstView () { |
||||
this.contracts = null |
||||
this.currentContractIndex = null |
||||
this.currentFunctionIndex = null |
||||
this.currentModifierIndex = null |
||||
this.isFunctionNotModifier = false |
||||
} |
||||
|
||||
abstractAstView.prototype.builder = function (relevantNodeFilter, contractsOut) { |
||||
this.contracts = contractsOut |
||||
return function (node) { |
||||
if (common.isContractDefinition(node)) { |
||||
setCurrentContract(this, { |
||||
node: node, |
||||
functions: [], |
||||
modifiers: [], |
||||
inheritsFrom: [], |
||||
stateVariables: common.getStateVariableDeclarationsFormContractNode(node) |
||||
}) |
||||
} else if (common.isInheritanceSpecifier(node)) { |
||||
var currentContract = getCurrentContract(this) |
||||
var inheritsFromName = common.getInheritsFromName(node) |
||||
currentContract.inheritsFrom.push(inheritsFromName) |
||||
// add variables from inherited contracts
|
||||
var inheritsFrom = this.contracts.find((contract) => common.getContractName(contract.node) === inheritsFromName) |
||||
currentContract.stateVariables = currentContract.stateVariables.concat(inheritsFrom.stateVariables) |
||||
} else if (common.isFunctionDefinition(node)) { |
||||
setCurrentFunction(this, { |
||||
node: node, |
||||
relevantNodes: [], |
||||
modifierInvocations: [], |
||||
localVariables: getLocalVariables(node), |
||||
parameters: getLocalParameters(node) |
||||
}) |
||||
} else if (common.isModifierDefinition(node)) { |
||||
setCurrentModifier(this, { |
||||
node: node, |
||||
relevantNodes: [], |
||||
localVariables: getLocalVariables(node), |
||||
parameters: getLocalParameters(node) |
||||
}) |
||||
} else if (common.isModifierInvocation(node)) { |
||||
if (!this.isFunctionNotModifier) throw new Error('abstractAstView.js: Found modifier invocation outside of function scope.') |
||||
getCurrentFunction(this).modifierInvocations.push(node) |
||||
} else if (relevantNodeFilter(node)) { |
||||
((this.isFunctionNotModifier) ? getCurrentFunction(this) : getCurrentModifier(this)).relevantNodes.push(node) |
||||
} |
||||
} |
||||
} |
||||
|
||||
function setCurrentContract (that, contract) { |
||||
that.currentContractIndex = (that.contracts.push(contract) - 1) |
||||
} |
||||
|
||||
function setCurrentFunction (that, func) { |
||||
that.isFunctionNotModifier = true |
||||
that.currentFunctionIndex = (getCurrentContract(that).functions.push(func) - 1) |
||||
} |
||||
|
||||
function setCurrentModifier (that, modi) { |
||||
that.isFunctionNotModifier = false |
||||
that.currentModifierIndex = (getCurrentContract(that).modifiers.push(modi) - 1) |
||||
} |
||||
|
||||
function getCurrentContract (that) { |
||||
return that.contracts[that.currentContractIndex] |
||||
} |
||||
|
||||
function getCurrentFunction (that) { |
||||
return getCurrentContract(that).functions[that.currentFunctionIndex] |
||||
} |
||||
|
||||
function getCurrentModifier (that) { |
||||
return getCurrentContract(that).modifiers[that.currentModifierIndex] |
||||
} |
||||
|
||||
function getLocalParameters (funcNode) { |
||||
return getLocalVariables(common.getFunctionOrModifierDefinitionParameterPart(funcNode)).map(common.getType) |
||||
} |
||||
|
||||
function getLocalVariables (funcNode) { |
||||
var locals = [] |
||||
new AstWalker().walk(funcNode, {'*': function (node) { |
||||
if (common.isVariableDeclaration(node)) locals.push(node) |
||||
return true |
||||
}}) |
||||
return locals |
||||
} |
||||
|
||||
module.exports = abstractAstView |
@ -1,4 +1,5 @@ |
||||
module.exports = { |
||||
SECURITY: {displayName: 'Security', id: 'SEC'}, |
||||
GAS: {displayName: 'Gas & Economy', id: 'GAS'} |
||||
GAS: {displayName: 'Gas & Economy', id: 'GAS'}, |
||||
MISC: {displayName: 'Miscellaneous', id: 'MISC'} |
||||
} |
||||
|
@ -0,0 +1,81 @@ |
||||
var name = 'Checks-Effects-Interaction pattern' |
||||
var desc = 'Avoid potential reentrancy bugs' |
||||
var categories = require('./categories') |
||||
var common = require('./staticAnalysisCommon') |
||||
var callGraph = require('./functionCallGraph') |
||||
var AbstractAst = require('./abstractAstView') |
||||
|
||||
function checksEffectsInteraction () { |
||||
this.contracts = [] |
||||
} |
||||
|
||||
checksEffectsInteraction.prototype.visit = new AbstractAst().builder( |
||||
(node) => common.isInteraction(node) || common.isEffect(node) || common.isLocalCall(node), |
||||
this.contracts |
||||
) |
||||
|
||||
checksEffectsInteraction.prototype.report = function (compilationResults) { |
||||
var warnings = [] |
||||
|
||||
var cg = callGraph.buildGlobalFuncCallGraph(this.contracts) |
||||
|
||||
this.contracts.forEach((contract) => { |
||||
contract.functions.forEach((func) => { |
||||
func.changesState = checkIfChangesState(common.getFullQuallyfiedFuncDefinitionIdent(contract.node, func.node, func.parameters), |
||||
getContext(cg, contract, func)) |
||||
}) |
||||
|
||||
contract.functions.forEach((func) => { |
||||
if (isPotentialVulnerableFunction(func, getContext(cg, contract, func))) { |
||||
var funcName = common.getFullQuallyfiedFuncDefinitionIdent(contract.node, func.node, func.parameters) |
||||
warnings.push({ |
||||
warning: `Potential Violation of Checks-Effects-Interaction pattern in <i>${funcName}</i>: Could potentially lead to re-entrancy vulnerability.`, |
||||
location: func.src, |
||||
more: 'http://solidity.readthedocs.io/en/develop/security-considerations.html#re-entrancy' |
||||
}) |
||||
} |
||||
}) |
||||
}) |
||||
|
||||
return warnings |
||||
} |
||||
|
||||
function getContext (cg, currentContract, func) { |
||||
return { cg: cg, currentContract: currentContract, stateVariables: getStateVariables(currentContract, func) } |
||||
} |
||||
|
||||
function getStateVariables (contract, func) { |
||||
return contract.stateVariables.concat(func.localVariables.filter(common.isStorageVariableDeclaration)) |
||||
} |
||||
|
||||
function isPotentialVulnerableFunction (func, context) { |
||||
var isPotentialVulnerable = false |
||||
var interaction = false |
||||
func.relevantNodes.forEach((node) => { |
||||
if (common.isInteraction(node)) { |
||||
interaction = true |
||||
} else if (interaction && (common.isWriteOnStateVariable(node, context.stateVariables) || isLocalCallWithStateChange(node, context))) { |
||||
isPotentialVulnerable = true |
||||
} |
||||
}) |
||||
return isPotentialVulnerable |
||||
} |
||||
|
||||
function isLocalCallWithStateChange (node, context) { |
||||
if (common.isLocalCall(node)) { |
||||
var func = callGraph.resolveCallGraphSymbol(context.cg, common.getFullQualifiedFunctionCallIdent(context.currentContract.node, node)) |
||||
return !func || (func && func.node.changesState) |
||||
} |
||||
return false |
||||
} |
||||
|
||||
function checkIfChangesState (startFuncName, context) { |
||||
return callGraph.analyseCallGraph(context.cg, startFuncName, context, (node, context) => common.isWriteOnStateVariable(node, context.stateVariables)) |
||||
} |
||||
|
||||
module.exports = { |
||||
name: name, |
||||
description: desc, |
||||
category: categories.SECURITY, |
||||
Module: checksEffectsInteraction |
||||
} |
@ -0,0 +1,86 @@ |
||||
var name = 'Constant functions' |
||||
var desc = 'Check for potentially constant functions' |
||||
var categories = require('./categories') |
||||
var common = require('./staticAnalysisCommon') |
||||
var callGraph = require('./functionCallGraph') |
||||
var AbstractAst = require('./abstractAstView') |
||||
|
||||
function constantFunctions () { |
||||
this.contracts = [] |
||||
} |
||||
|
||||
constantFunctions.prototype.visit = new AbstractAst().builder( |
||||
(node) => common.isLowLevelCall(node) || common.isExternalDirectCall(node) || common.isEffect(node) || common.isLocalCall(node) || common.isInlineAssembly(node), |
||||
this.contracts |
||||
) |
||||
|
||||
constantFunctions.prototype.report = function (compilationResults) { |
||||
var warnings = [] |
||||
|
||||
var cg = callGraph.buildGlobalFuncCallGraph(this.contracts) |
||||
|
||||
this.contracts.forEach((contract) => { |
||||
if (!common.isFullyImplementedContract(contract.node)) return |
||||
|
||||
contract.functions.forEach((func) => { |
||||
func.potentiallyshouldBeConst = checkIfShouldBeConstant(common.getFullQuallyfiedFuncDefinitionIdent(contract.node, func.node, func.parameters), |
||||
getContext(cg, contract, func)) |
||||
}) |
||||
|
||||
contract.functions.forEach((func) => { |
||||
if (common.isConstantFunction(func.node) !== func.potentiallyshouldBeConst) { |
||||
var funcName = common.getFullQuallyfiedFuncDefinitionIdent(contract.node, func.node, func.parameters) |
||||
if (func.potentiallyshouldBeConst) { |
||||
warnings.push({ |
||||
warning: `<i>${funcName}</i>: Potentially should be constant but is not.`, |
||||
location: func.src, |
||||
more: 'http://solidity.readthedocs.io/en/develop/contracts.html#constant-functions' |
||||
}) |
||||
} else { |
||||
warnings.push({ |
||||
warning: `<i>${funcName}</i>: Is constant but potentially should not be.`, |
||||
location: func.src, |
||||
more: 'http://solidity.readthedocs.io/en/develop/contracts.html#constant-functions' |
||||
}) |
||||
} |
||||
} |
||||
}) |
||||
}) |
||||
|
||||
return warnings |
||||
} |
||||
|
||||
function getContext (cg, currentContract, func) { |
||||
return { cg: cg, currentContract: currentContract, stateVariables: getStateVariables(currentContract, func) } |
||||
} |
||||
|
||||
function getStateVariables (contract, func) { |
||||
return contract.stateVariables.concat(func.localVariables.filter(common.isStorageVariableDeclaration)) |
||||
} |
||||
|
||||
function checkIfShouldBeConstant (startFuncName, context) { |
||||
return !callGraph.analyseCallGraph(context.cg, startFuncName, context, isConstBreaker) |
||||
} |
||||
|
||||
function isConstBreaker (node, context) { |
||||
return common.isWriteOnStateVariable(node, context.stateVariables) || |
||||
common.isLowLevelCall(node) || |
||||
isCallOnNonConstExternalInterfaceFunction(node, context) || |
||||
common.isCallToNonConstLocalFunction(node) || |
||||
common.isInlineAssembly(node) |
||||
} |
||||
|
||||
function isCallOnNonConstExternalInterfaceFunction (node, context) { |
||||
if (common.isExternalDirectCall(node)) { |
||||
var func = callGraph.resolveCallGraphSymbol(context.cg, common.getFullQualifiedFunctionCallIdent(context.currentContract, node)) |
||||
return !func || (func && !common.isConstantFunction(func.node.node)) |
||||
} |
||||
return false |
||||
} |
||||
|
||||
module.exports = { |
||||
name: name, |
||||
description: desc, |
||||
category: categories.MISC, |
||||
Module: constantFunctions |
||||
} |
@ -0,0 +1,84 @@ |
||||
'use strict' |
||||
|
||||
var common = require('./staticAnalysisCommon') |
||||
|
||||
function buildLocalFuncCallGraphInternal (functions, nodeFilter, extractNodeIdent, extractFuncDefIdent) { |
||||
var callGraph = {} |
||||
functions.forEach((func) => { |
||||
var calls = func.relevantNodes |
||||
.filter(nodeFilter) |
||||
.map(extractNodeIdent) |
||||
.filter((name) => name !== extractFuncDefIdent(func)) // filter self recursive call
|
||||
|
||||
callGraph[extractFuncDefIdent(func)] = { node: func, calls: calls } |
||||
}) |
||||
|
||||
return callGraph |
||||
} |
||||
|
||||
function buildGlobalFuncCallGraph (contracts) { |
||||
var callGraph = {} |
||||
contracts.forEach((contract) => { |
||||
var filterNodes = (node) => { return common.isLocalCall(node) || common.isThisLocalCall(node) || common.isExternalDirectCall(node) } |
||||
var getNodeIdent = (node) => { return common.getFullQualifiedFunctionCallIdent(contract.node, node) } |
||||
var getFunDefIdent = (funcDef) => { return common.getFullQuallyfiedFuncDefinitionIdent(contract.node, funcDef.node, funcDef.parameters) } |
||||
|
||||
callGraph[common.getContractName(contract.node)] = { contract: contract, functions: buildLocalFuncCallGraphInternal(contract.functions, filterNodes, getNodeIdent, getFunDefIdent) } |
||||
}) |
||||
|
||||
return callGraph |
||||
} |
||||
|
||||
function analyseCallGraph (cg, funcName, context, nodeCheck) { |
||||
return analyseCallGraphInternal(cg, funcName, context, (a, b) => a || b, nodeCheck, {}) |
||||
} |
||||
|
||||
function analyseCallGraphInternal (cg, funcName, context, combinator, nodeCheck, visited) { |
||||
var current = resolveCallGraphSymbol(cg, funcName) |
||||
|
||||
if (!current || visited[funcName]) return true |
||||
visited[funcName] = true |
||||
|
||||
return combinator(current.node.relevantNodes.reduce((acc, val) => combinator(acc, nodeCheck(val, context)), false), |
||||
current.calls.reduce((acc, val) => combinator(acc, analyseCallGraphInternal(cg, val, context, combinator, nodeCheck, visited)), false)) |
||||
} |
||||
|
||||
function resolveCallGraphSymbol (cg, funcName) { |
||||
return resolveCallGraphSymbolInternal(cg, funcName, false) |
||||
} |
||||
|
||||
function resolveCallGraphSymbolInternal (cg, funcName, silent) { |
||||
var current = null |
||||
if (funcName.includes('.')) { |
||||
var parts = funcName.split('.') |
||||
var contractPart = parts[0] |
||||
var functionPart = parts[1] |
||||
var currentContract = cg[contractPart] |
||||
if (currentContract) { |
||||
current = currentContract.functions[funcName] |
||||
// resolve inheritance hierarchy
|
||||
if (!current) { |
||||
// resolve inheritance lookup in linearized fashion
|
||||
var inheritsFromNames = currentContract.contract.inheritsFrom.reverse() |
||||
for (var i = 0; i < inheritsFromNames.length; i++) { |
||||
var res = resolveCallGraphSymbolInternal(cg, inheritsFromNames[i] + '.' + functionPart, true) |
||||
if (res) return res |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
throw new Error('functionCallGraph.js: function does not have full qualified name.') |
||||
} |
||||
if (!current) { |
||||
if (!silent) console.log(`static analysis functionCallGraph.js: ${funcName} not found in function call graph.`) |
||||
return null |
||||
} else { |
||||
return current |
||||
} |
||||
} |
||||
|
||||
module.exports = { |
||||
analyseCallGraph: analyseCallGraph, |
||||
buildGlobalFuncCallGraph: buildGlobalFuncCallGraph, |
||||
resolveCallGraphSymbol: resolveCallGraphSymbol |
||||
} |
@ -0,0 +1,29 @@ |
||||
var name = 'Inline Assembly' |
||||
var desc = 'Use of Inline Assembly' |
||||
var categories = require('./categories') |
||||
var common = require('./staticAnalysisCommon') |
||||
|
||||
function inlineAssembly () { |
||||
this.inlineAssNodes = [] |
||||
} |
||||
|
||||
inlineAssembly.prototype.visit = function (node) { |
||||
if (common.isInlineAssembly(node)) this.inlineAssNodes.push(node) |
||||
} |
||||
|
||||
inlineAssembly.prototype.report = function (compilationResults) { |
||||
return this.inlineAssNodes.map((node) => { |
||||
return { |
||||
warning: `CAUTION: The Contract uses inline assembly, this is only advised in rare cases. Additionally static analysis modules do not parse inline Assembly, this can lead to wrong analysis results.`, |
||||
location: node.src, |
||||
more: 'http://solidity.readthedocs.io/en/develop/assembly.html#solidity-assembly' |
||||
} |
||||
}) |
||||
} |
||||
|
||||
module.exports = { |
||||
name: name, |
||||
description: desc, |
||||
category: categories.SECURITY, |
||||
Module: inlineAssembly |
||||
} |
@ -1,5 +1,8 @@ |
||||
module.exports = [ |
||||
require('./txOrigin'), |
||||
require('./gasCosts'), |
||||
require('./thisLocal') |
||||
require('./thisLocal'), |
||||
require('./checksEffectsInteraction'), |
||||
require('./constantFunctions'), |
||||
require('./inlineAssembly') |
||||
] |
||||
|
@ -0,0 +1,47 @@ |
||||
// var test = require('tape')
|
||||
|
||||
// var common = require('../../babelify-src/app/staticanalysis/modules/staticAnalysisCommon')
|
||||
// var StatRunner = require('../../babelify-src/app/staticanalysis/staticAnalysisRunner')
|
||||
// var utils = require('../../babelify-src/app/utils')
|
||||
// var Compiler = require('../../babelify-src/app/compiler')
|
||||
|
||||
// var fs = require('fs')
|
||||
// var path = require('path')
|
||||
|
||||
// var testFiles = [
|
||||
// '/test-contracts/KingOfTheEtherThrone.sol',
|
||||
// '/test-contracts/assembly.sol',
|
||||
// '/test-contracts/ballot.sol',
|
||||
// '/test-contracts/ballot_reentrant.sol',
|
||||
// '/test-contracts/ballot_withoutWarning.sol',
|
||||
// '/test-contracts/cross_contract.sol',
|
||||
// '/test-contracts/inheritance.sol',
|
||||
// '/test-contracts/notReentrant.sol',
|
||||
// '/test-contracts/structReentrant.sol',
|
||||
// '/test-contracts/thisLocal.sol',
|
||||
// '/test-contracts/modifier1.sol',
|
||||
// '/test-contracts/modifier2.sol'
|
||||
// ]
|
||||
|
||||
// test('thisLocal.js', function (t) {
|
||||
// t.plan(0)
|
||||
|
||||
// var module = require('../../babelify-src/app/staticanalysis/modules/thisLocal')
|
||||
|
||||
// runModuleOnFiles(module, t)
|
||||
// })
|
||||
|
||||
// function runModuleOnFiles (module, t) {
|
||||
// var fakeImport = function (url, cb) { cb('Not implemented') }
|
||||
// var compiler = new Compiler(fakeImport)
|
||||
// var statRunner = new StatRunner()
|
||||
|
||||
// testFiles.map((fileName) => {
|
||||
// var contents = fs.readFileSync(path.join(__dirname, fileName), 'utf8')
|
||||
// var compres = compiler.compile({ 'test': contents }, 'test')
|
||||
|
||||
// statRunner.runWithModuleList(compres, [{ name: module.name, mod: new module.Module() }], (reports) => {
|
||||
// reports.map((r) => t.comment(r.warning))
|
||||
// })
|
||||
// })
|
||||
// }
|
@ -0,0 +1,23 @@ |
||||
// return value send |
||||
contract KingOfTheEtherThrone{ |
||||
struct Monarch { |
||||
// address of the king . |
||||
address ethAddr ; |
||||
string name ; |
||||
// how much he pays to previous king |
||||
uint claimPrice ; |
||||
uint coronationTimestamp; |
||||
} |
||||
Monarch public currentMonarch ; |
||||
|
||||
function claimThrone ( string name ) { |
||||
address wizardAddress; |
||||
uint compensation = 100; |
||||
uint valuePaid = 10; |
||||
|
||||
if ( currentMonarch.ethAddr != wizardAddress ) |
||||
if (currentMonarch.ethAddr.send( compensation )) throw; |
||||
|
||||
currentMonarch = Monarch(msg.sender,name,valuePaid,block.timestamp); |
||||
} |
||||
} |
@ -0,0 +1,26 @@ |
||||
pragma solidity ^0.4.9; |
||||
contract test { |
||||
|
||||
function at(address _addr) returns (bytes o_code) { |
||||
assembly { |
||||
// retrieve the size of the code, this needs assembly |
||||
let size := extcodesize(_addr) |
||||
// allocate output byte array - this could also be done without assembly |
||||
// by using o_code = new bytes(size) |
||||
o_code := mload(0x40) |
||||
// new "memory end" including padding |
||||
mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) |
||||
// store length in memory |
||||
mstore(o_code, size) |
||||
// actually retrieve the code, this needs assembly |
||||
extcodecopy(_addr, add(o_code, 0x20), 0, size) |
||||
} |
||||
} |
||||
|
||||
function bla() { |
||||
msg.sender.send(19); |
||||
assembly { |
||||
|
||||
} |
||||
} |
||||
} |
@ -0,0 +1,145 @@ |
||||
pragma solidity ^0.4.0; |
||||
|
||||
/// @title Voting with delegation. |
||||
contract Ballot { |
||||
// This declares a new complex type which will |
||||
// be used for variables later. |
||||
// It will represent a single voter. |
||||
struct Voter { |
||||
uint weight; // weight is accumulated by delegation |
||||
bool voted; // if true, that person already voted |
||||
address delegate; // person delegated to |
||||
uint vote; // index of the voted proposal |
||||
} |
||||
|
||||
// This is a type for a single proposal. |
||||
struct Proposal |
||||
{ |
||||
bytes32 name; // short name (up to 32 bytes) |
||||
uint voteCount; // number of accumulated votes |
||||
} |
||||
|
||||
address public chairperson; |
||||
|
||||
// This declares a state variable that |
||||
// stores a `Voter` struct for each possible address. |
||||
mapping(address => Voter) public voters; |
||||
|
||||
// A dynamically-sized array of `Proposal` structs. |
||||
Proposal[] public proposals; |
||||
|
||||
/// Create a new ballot to choose one of `proposalNames`. |
||||
function Ballot(bytes32[] proposalNames) { |
||||
chairperson = msg.sender; |
||||
voters[chairperson].weight = 1; |
||||
|
||||
// For each of the provided proposal names, |
||||
// create a new proposal object and add it |
||||
// to the end of the array. |
||||
for (uint i = 0; i < proposalNames.length; i++) { |
||||
// `Proposal({...})` creates a temporary |
||||
// Proposal object and `proposals.push(...)` |
||||
// appends it to the end of `proposals`. |
||||
proposals.push(Proposal({ |
||||
name: proposalNames[i], |
||||
voteCount: 0 |
||||
})); |
||||
} |
||||
} |
||||
|
||||
// Give `voter` the right to vote on this ballot. |
||||
// May only be called by `chairperson`. |
||||
function giveRightToVote(address voter) { |
||||
if (msg.sender != chairperson || voters[voter].voted) { |
||||
// `throw` terminates and reverts all changes to |
||||
// the state and to Ether balances. It is often |
||||
// a good idea to use this if functions are |
||||
// called incorrectly. But watch out, this |
||||
// will also consume all provided gas. |
||||
throw; |
||||
} |
||||
voters[voter].weight = 1; |
||||
} |
||||
|
||||
/// Delegate your vote to the voter `to`. |
||||
function delegate(address to) { |
||||
// assigns reference |
||||
Voter sender = voters[msg.sender]; |
||||
if (sender.voted) |
||||
throw; |
||||
|
||||
// Forward the delegation as long as |
||||
// `to` also delegated. |
||||
// In general, such loops are very dangerous, |
||||
// because if they run too long, they might |
||||
// need more gas than is available in a block. |
||||
// In this case, the delegation will not be executed, |
||||
// but in other situations, such loops might |
||||
// cause a contract to get "stuck" completely. |
||||
while ( |
||||
voters[to].delegate != address(0) && |
||||
voters[to].delegate != msg.sender |
||||
) { |
||||
to = voters[to].delegate; |
||||
} |
||||
|
||||
// We found a loop in the delegation, not allowed. |
||||
if (to == msg.sender) { |
||||
throw; |
||||
} |
||||
|
||||
// Since `sender` is a reference, this |
||||
// modifies `voters[msg.sender].voted` |
||||
sender.voted = true; |
||||
sender.delegate = to; |
||||
Voter delegate = voters[to]; |
||||
if (delegate.voted) { |
||||
// If the delegate already voted, |
||||
// directly add to the number of votes |
||||
proposals[delegate.vote].voteCount += sender.weight; |
||||
} else { |
||||
// If the delegate did not vote yet, |
||||
// add to her weight. |
||||
delegate.weight += sender.weight; |
||||
} |
||||
} |
||||
|
||||
/// Give your vote (including votes delegated to you) |
||||
/// to proposal `proposals[proposal].name`. |
||||
function vote(uint proposal) { |
||||
Voter sender = voters[msg.sender]; |
||||
if (sender.voted) |
||||
throw; |
||||
sender.voted = true; |
||||
sender.vote = proposal; |
||||
|
||||
// If `proposal` is out of the range of the array, |
||||
// this will throw automatically and revert all |
||||
// changes. |
||||
proposals[proposal].voteCount += sender.weight; |
||||
} |
||||
|
||||
/// @dev Computes the winning proposal taking all |
||||
/// previous votes into account. |
||||
function winningProposal() constant |
||||
returns (uint winningProposal) |
||||
{ |
||||
uint winningVoteCount = 0; |
||||
for (uint p = 0; p < proposals.length; p++) { |
||||
if (proposals[p].voteCount > winningVoteCount) { |
||||
winningVoteCount = proposals[p].voteCount; |
||||
winningProposal = p; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Calls winningProposal() function to get the index |
||||
// of the winner contained in the proposals array and then |
||||
// returns the name of the winner |
||||
function winnerName() constant |
||||
returns (bytes32 winnerName) |
||||
{ |
||||
winnerName = proposals[winningProposal()].name; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,101 @@ |
||||
pragma solidity ^0.4.0; |
||||
|
||||
contract InfoFeed { |
||||
function info() payable returns (uint ret); |
||||
function call1(uint a) payable returns (bool); |
||||
} |
||||
|
||||
|
||||
contract Ballot { |
||||
|
||||
InfoFeed feed; |
||||
|
||||
struct Voter { |
||||
uint weight; |
||||
bool voted; |
||||
uint8 vote; |
||||
address delegate; |
||||
} |
||||
struct Proposal { |
||||
uint voteCount; |
||||
} |
||||
|
||||
address chairperson; |
||||
mapping(address => Voter) voters; |
||||
Proposal[] proposals; |
||||
|
||||
function send1(address a) { |
||||
giveRightToVote(a,a); |
||||
} |
||||
|
||||
/// Create a new ballot with $(_numProposals) different proposals. |
||||
function Ballot(uint8 _numProposals) { |
||||
address d; |
||||
if(!d.delegatecall.gas(800)('function_name', 'arg1', 'arg2')) throw; |
||||
if(!d.callcode.gas(800)('function_name', 'arg1', 'arg2')) throw; |
||||
if(!d.call.value(10).gas(800)('function_name', 'arg1', 'arg2')) throw; |
||||
if(!d.call.value(10).gas(800)('function_name', 'arg1', 'arg2')) throw; |
||||
|
||||
|
||||
|
||||
if(!msg.sender.send(1 wei)) throw; |
||||
if(!d.call('function_name', 'arg1', 'arg2')) throw; |
||||
|
||||
|
||||
uint a = now; |
||||
uint c = block.timestamp; |
||||
if(block.timestamp < 100){} |
||||
chairperson = msg.sender; |
||||
voters[chairperson].weight = 1; |
||||
proposals.length = _numProposals; |
||||
if(!d.send(1 wei)) throw; |
||||
feed.info.value(10).gas(800)(); |
||||
|
||||
feed.call1(1); |
||||
|
||||
this.send1(d); |
||||
} |
||||
|
||||
|
||||
/// Give $(voter) the right to vote on this ballot. |
||||
/// May only be called by $(chairperson). |
||||
function giveRightToVote(address voter, address b) payable returns (bool){ |
||||
if (msg.sender != chairperson || voters[voter].voted) return; |
||||
voters[voter].weight = 1; |
||||
return true; |
||||
} |
||||
|
||||
/// Delegate your vote to the voter $(to). |
||||
function delegate(address to) { |
||||
Voter sender = voters[msg.sender]; // assigns reference |
||||
if (sender.voted) return; |
||||
while (voters[to].delegate != address(0) && voters[to].delegate != msg.sender) |
||||
to = voters[to].delegate; |
||||
if (to == msg.sender) return; |
||||
sender.voted = true; |
||||
sender.delegate = to; |
||||
Voter delegate = voters[to]; |
||||
if (delegate.voted) |
||||
proposals[delegate.vote].voteCount += sender.weight; |
||||
else |
||||
delegate.weight += sender.weight; |
||||
} |
||||
|
||||
/// Give a single vote to proposal $(proposal). |
||||
function vote(uint8 proposal) { |
||||
Voter sender = voters[msg.sender]; |
||||
if (sender.voted || proposal >= proposals.length) return; |
||||
sender.voted = true; |
||||
sender.vote = proposal; |
||||
proposals[proposal].voteCount += sender.weight; |
||||
} |
||||
|
||||
function winningProposal() constant returns (uint8 winningProposal) { |
||||
uint256 winningVoteCount = 0; |
||||
for (uint8 proposal = 0; proposal < proposals.length; proposal++) |
||||
if (proposals[proposal].voteCount > winningVoteCount) { |
||||
winningVoteCount = proposals[proposal].voteCount; |
||||
winningProposal = proposal; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,31 @@ |
||||
pragma solidity ^0.4.0; |
||||
|
||||
/// @title Voting with delegation. |
||||
contract Ballot { |
||||
|
||||
struct Proposal |
||||
{ |
||||
bytes32 name; // short name (up to 32 bytes) |
||||
uint voteCount; // number of accumulated votes |
||||
} |
||||
|
||||
// A dynamically-sized array of `Proposal` structs. |
||||
Proposal[] public proposals; |
||||
|
||||
/// @dev Computes the winning proposal taking all |
||||
/// previous votes into account. |
||||
function winningProposal() constant |
||||
returns (uint winningProposal) |
||||
{ |
||||
winningProposal = 0; |
||||
} |
||||
|
||||
// Calls winningProposal() function to get the index |
||||
// of the winner contained in the proposals array and then |
||||
// returns the name of the winner |
||||
function winnerName() constant |
||||
returns (bytes32 winnerName) |
||||
{ |
||||
winnerName = proposals[winningProposal()].name; |
||||
} |
||||
} |
@ -0,0 +1,19 @@ |
||||
pragma solidity ^0.4.0; |
||||
|
||||
contract a { |
||||
|
||||
uint x; |
||||
|
||||
function foo() { |
||||
x++; |
||||
} |
||||
} |
||||
|
||||
contract b { |
||||
a x; |
||||
function bar() constant { |
||||
address a; |
||||
a.send(100 wei); |
||||
x.foo(); |
||||
} |
||||
} |
@ -0,0 +1,40 @@ |
||||
pragma solidity ^0.4.9; |
||||
|
||||
contract r { |
||||
function s() constant {} |
||||
} |
||||
|
||||
contract a is r { |
||||
uint x = 1; |
||||
|
||||
function getX() constant returns (uint) { |
||||
return x; |
||||
} |
||||
} |
||||
|
||||
contract b is a { |
||||
uint y = 2; |
||||
uint x = 3; |
||||
|
||||
|
||||
function getY(uint z, bool r) returns (uint) { |
||||
return y++; |
||||
} |
||||
|
||||
function getY(string storage n) internal constant returns (uint) { return 10; } |
||||
|
||||
} |
||||
|
||||
contract c is b { |
||||
string x; |
||||
|
||||
function d() returns (uint a, uint b) { |
||||
//d(); |
||||
//sha3("bla"); |
||||
msg.sender.call.gas(200000).value(this.balance)(bytes4(sha3("pay()"))); |
||||
//x++; |
||||
getY(x); |
||||
a = getX() + getY(1, false); |
||||
b = getX() + getY(x); |
||||
} |
||||
} |
@ -0,0 +1,17 @@ |
||||
pragma solidity ^0.4.0; |
||||
|
||||
contract test { |
||||
|
||||
address owner; |
||||
|
||||
modifier onlyOwner { |
||||
var a = 0; |
||||
if (msg.sender != owner) |
||||
throw; |
||||
_; |
||||
} |
||||
|
||||
function b(address a) onlyOwner returns (bool) { |
||||
|
||||
} |
||||
} |
@ -0,0 +1,28 @@ |
||||
pragma solidity ^0.4.0; |
||||
|
||||
contract owned { |
||||
|
||||
uint r=0; |
||||
|
||||
modifier ntimes(uint n) { |
||||
for(uint i=0;i<n-1;i++){ |
||||
_; |
||||
} |
||||
_; |
||||
} |
||||
|
||||
modifier plus100 { |
||||
var bla=1; |
||||
r+=100; |
||||
_; |
||||
} |
||||
|
||||
function a() ntimes(10) plus100 payable returns (uint) { |
||||
{ |
||||
uint bla=5; |
||||
} |
||||
r += bla; |
||||
return r; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,13 @@ |
||||
pragma solidity ^0.4.0; |
||||
|
||||
contract Fund { |
||||
/// Mapping of ether shares of the contract. |
||||
mapping(address => uint) shares; |
||||
/// Withdraw your share. |
||||
function withdraw() { |
||||
var share = shares[msg.sender]; |
||||
shares[msg.sender] = 0; |
||||
if (!msg.sender.send(share)) |
||||
throw; |
||||
} |
||||
} |
@ -0,0 +1,49 @@ |
||||
pragma solidity ^0.4.0; |
||||
|
||||
contract InfoFeed { |
||||
uint c; |
||||
function info() constant returns (uint ret) {return c;} |
||||
function call1(uint a) constant returns (bool) {return true;} |
||||
} |
||||
|
||||
// THIS CONTRACT CONTAINS A BUG - DO NOT USE |
||||
contract Fund { |
||||
/// Mapping of ether shares of the contract. |
||||
//mapping(address => uint) shares; |
||||
/// Withdraw your share. |
||||
|
||||
uint c = 0; |
||||
function withdraw() constant { |
||||
InfoFeed f; |
||||
|
||||
|
||||
//shares[msg.sender] /= 1; |
||||
|
||||
f.info(); |
||||
|
||||
//if (msg.sender.send(shares[msg.sender])) throw; |
||||
// shares[msg.sender] = 0; |
||||
|
||||
|
||||
b(true, false); |
||||
//shares[msg.sender]++; |
||||
//c++; |
||||
|
||||
} |
||||
mapping(address => uint) shares; |
||||
|
||||
function b(bool a, bool b) returns (bool) { |
||||
mapping(address => uint) c = shares; |
||||
c[msg.sender] = 0; |
||||
//f(); |
||||
//withdraw(); |
||||
//shares[msg.sender]++; |
||||
//c++; |
||||
return true; |
||||
} |
||||
|
||||
function f() { |
||||
c++; |
||||
withdraw(); |
||||
} |
||||
} |
@ -0,0 +1,36 @@ |
||||
pragma solidity ^0.4.9; |
||||
|
||||
contract Ballot { |
||||
|
||||
struct Voter { |
||||
uint weight; |
||||
bool voted; |
||||
uint8 vote; |
||||
address delegate; |
||||
baz foo; |
||||
} |
||||
|
||||
struct baz{ |
||||
uint bar; |
||||
} |
||||
|
||||
mapping(address => Voter) voters; |
||||
|
||||
/// Create a new ballot with $(_numProposals) different proposals. |
||||
function bla(address a) { |
||||
Voter x = voters[a]; |
||||
|
||||
if (!a.send(10)) |
||||
throw; |
||||
|
||||
//voters[a] = Voter(10,true,1,a); |
||||
//x.foo.bar *= 100; |
||||
bli(x); |
||||
} |
||||
|
||||
//function bla(){} |
||||
|
||||
function bli(Voter storage x) private { |
||||
x.foo.bar++; |
||||
} |
||||
} |
@ -0,0 +1,16 @@ |
||||
pragma solidity ^0.4.0; |
||||
|
||||
contract test { |
||||
|
||||
function (){ |
||||
address x; |
||||
this.b(x); |
||||
x.call('something'); |
||||
x.send(1 wei); |
||||
|
||||
} |
||||
|
||||
function b(address a) returns (bool) { |
||||
|
||||
} |
||||
} |
Loading…
Reference in new issue