aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2015-08-04 18:43:40 +0800
committerchriseth <c@ethdev.com>2015-08-04 22:31:39 +0800
commitf2088278aab0c703510814f0f4a59009942ec053 (patch)
treebbc30c6cd2c577b78757111035fe138bb0f61471 /libsolidity
parent765f30368837e3e930d6a221d870a277278e5c3f (diff)
downloaddexon-solidity-f2088278aab0c703510814f0f4a59009942ec053.tar.gz
dexon-solidity-f2088278aab0c703510814f0f4a59009942ec053.tar.zst
dexon-solidity-f2088278aab0c703510814f0f4a59009942ec053.zip
Break off contract tests.
Diffstat (limited to 'libsolidity')
-rw-r--r--libsolidity/SolidityFixedFeeRegistrar.cpp237
-rw-r--r--libsolidity/SolidityWallet.cpp668
2 files changed, 0 insertions, 905 deletions
diff --git a/libsolidity/SolidityFixedFeeRegistrar.cpp b/libsolidity/SolidityFixedFeeRegistrar.cpp
deleted file mode 100644
index 26373499..00000000
--- a/libsolidity/SolidityFixedFeeRegistrar.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- This file is part of cpp-ethereum.
-
- cpp-ethereum is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- cpp-ethereum is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
-*/
-/**
- * @author Christian <c@ethdev.com>
- * @date 2015
- * Tests for a fixed fee registrar contract.
- */
-
-#include <string>
-#include <tuple>
-#include <boost/test/unit_test.hpp>
-#include <libdevcore/Hash.h>
-#include <test/libsolidity/solidityExecutionFramework.h>
-
-using namespace std;
-
-namespace dev
-{
-namespace solidity
-{
-namespace test
-{
-
-static char const* registrarCode = R"DELIMITER(
-//sol FixedFeeRegistrar
-// Simple global registrar with fixed-fee reservations.
-// @authors:
-// Gav Wood <g@ethdev.com>
-
-contract Registrar {
- event Changed(string indexed name);
-
- function owner(string _name) constant returns (address o_owner);
- function addr(string _name) constant returns (address o_address);
- function subRegistrar(string _name) constant returns (address o_subRegistrar);
- function content(string _name) constant returns (bytes32 o_content);
-}
-
-contract FixedFeeRegistrar is Registrar {
- struct Record {
- address addr;
- address subRegistrar;
- bytes32 content;
- address owner;
- }
-
- modifier onlyrecordowner(string _name) { if (m_record(_name).owner == msg.sender) _ }
-
- function reserve(string _name) {
- Record rec = m_record(_name);
- if (rec.owner == 0 && msg.value >= c_fee) {
- rec.owner = msg.sender;
- Changed(_name);
- }
- }
- function disown(string _name, address _refund) onlyrecordowner(_name) {
- delete m_recordData[uint(sha3(_name)) / 8];
- _refund.send(c_fee);
- Changed(_name);
- }
- function transfer(string _name, address _newOwner) onlyrecordowner(_name) {
- m_record(_name).owner = _newOwner;
- Changed(_name);
- }
- function setAddr(string _name, address _a) onlyrecordowner(_name) {
- m_record(_name).addr = _a;
- Changed(_name);
- }
- function setSubRegistrar(string _name, address _registrar) onlyrecordowner(_name) {
- m_record(_name).subRegistrar = _registrar;
- Changed(_name);
- }
- function setContent(string _name, bytes32 _content) onlyrecordowner(_name) {
- m_record(_name).content = _content;
- Changed(_name);
- }
-
- function record(string _name) constant returns (address o_addr, address o_subRegistrar, bytes32 o_content, address o_owner) {
- Record rec = m_record(_name);
- o_addr = rec.addr;
- o_subRegistrar = rec.subRegistrar;
- o_content = rec.content;
- o_owner = rec.owner;
- }
- function addr(string _name) constant returns (address) { return m_record(_name).addr; }
- function subRegistrar(string _name) constant returns (address) { return m_record(_name).subRegistrar; }
- function content(string _name) constant returns (bytes32) { return m_record(_name).content; }
- function owner(string _name) constant returns (address) { return m_record(_name).owner; }
-
- Record[2**253] m_recordData;
- function m_record(string _name) constant internal returns (Record storage o_record) {
- return m_recordData[uint(sha3(_name)) / 8];
- }
- uint constant c_fee = 69 ether;
-}
-)DELIMITER";
-
-static unique_ptr<bytes> s_compiledRegistrar;
-
-class RegistrarTestFramework: public ExecutionFramework
-{
-protected:
- void deployRegistrar()
- {
- if (!s_compiledRegistrar)
- {
- m_optimize = true;
- m_compiler.reset(false, m_addStandardSources);
- m_compiler.addSource("", registrarCode);
- ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize, m_optimizeRuns), "Compiling contract failed");
- s_compiledRegistrar.reset(new bytes(m_compiler.getBytecode("FixedFeeRegistrar")));
- }
- sendMessage(*s_compiledRegistrar, true);
- BOOST_REQUIRE(!m_output.empty());
- }
- u256 const m_fee = u256("69000000000000000000");
-};
-
-/// This is a test suite that tests optimised code!
-BOOST_FIXTURE_TEST_SUITE(SolidityFixedFeeRegistrar, RegistrarTestFramework)
-
-BOOST_AUTO_TEST_CASE(creation)
-{
- deployRegistrar();
-}
-
-BOOST_AUTO_TEST_CASE(reserve)
-{
- // Test that reserving works and fee is taken into account.
- deployRegistrar();
- string name[] = {"abc", "def", "ghi"};
- m_sender = Address(0x123);
- BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name[0])) == encodeArgs());
- BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[0])) == encodeArgs(h256(0x123)));
- BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee + 1, encodeDyn(name[1])) == encodeArgs());
- BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[1])) == encodeArgs(h256(0x123)));
- BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee - 1, encodeDyn(name[2])) == encodeArgs());
- BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[2])) == encodeArgs(h256(0)));
-}
-
-BOOST_AUTO_TEST_CASE(double_reserve)
-{
- // Test that it is not possible to re-reserve from a different address.
- deployRegistrar();
- string name = "abc";
- m_sender = Address(0x123);
- BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
- BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(h256(0x123)));
-
- m_sender = Address(0x124);
- BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
- BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(h256(0x123)));
-}
-
-BOOST_AUTO_TEST_CASE(properties)
-{
- // Test setting and retrieving the various properties works.
- deployRegistrar();
- string names[] = {"abc", "def", "ghi"};
- size_t addr = 0x9872543;
- for (string const& name: names)
- {
- addr++;
- size_t sender = addr + 10007;
- m_sender = Address(sender);
- // setting by sender works
- BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
- BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(u256(sender)));
- BOOST_CHECK(callContractFunction("setAddr(string,address)", u256(0x40), u256(addr), u256(name.length()), name) == encodeArgs());
- BOOST_CHECK(callContractFunction("addr(string)", encodeDyn(name)) == encodeArgs(addr));
- BOOST_CHECK(callContractFunction("setSubRegistrar(string,address)", u256(0x40), addr + 20, u256(name.length()), name) == encodeArgs());
- BOOST_CHECK(callContractFunction("subRegistrar(string)", encodeDyn(name)) == encodeArgs(addr + 20));
- BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), addr + 90, u256(name.length()), name) == encodeArgs());
- BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(addr + 90));
- // but not by someone else
- m_sender = Address(h256(addr + 10007 - 1));
- BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(sender));
- BOOST_CHECK(callContractFunction("setAddr(string,address)", u256(0x40), addr + 1, u256(name.length()), name) == encodeArgs());
- BOOST_CHECK(callContractFunction("addr(string)", encodeDyn(name)) == encodeArgs(addr));
- BOOST_CHECK(callContractFunction("setSubRegistrar(string,address)", u256(0x40), addr + 20 + 1, u256(name.length()), name) == encodeArgs());
- BOOST_CHECK(callContractFunction("subRegistrar(string)", encodeDyn(name)) == encodeArgs(addr + 20));
- BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), addr + 90 + 1, u256(name.length()), name) == encodeArgs());
- BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(addr + 90));
- }
-}
-
-BOOST_AUTO_TEST_CASE(transfer)
-{
- deployRegistrar();
- string name = "abc";
- m_sender = Address(0x123);
- BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
- BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), u256(123), u256(name.length()), name) == encodeArgs());
- BOOST_CHECK(callContractFunction("transfer(string,address)", u256(0x40), u256(555), u256(name.length()), name) == encodeArgs());
- BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(u256(555)));
- BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(u256(123)));
-}
-
-BOOST_AUTO_TEST_CASE(disown)
-{
- deployRegistrar();
- string name = "abc";
- m_sender = Address(0x123);
- BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
- BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), u256(123), u256(name.length()), name) == encodeArgs());
- BOOST_CHECK(callContractFunction("setAddr(string,address)", u256(0x40), u256(124), u256(name.length()), name) == encodeArgs());
- BOOST_CHECK(callContractFunction("setSubRegistrar(string,address)", u256(0x40), u256(125), u256(name.length()), name) == encodeArgs());
-
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x124)), 0);
- BOOST_CHECK(callContractFunction("disown(string,address)", u256(0x40), u256(0x124), name.size(), name) == encodeArgs());
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x124)), m_fee);
-
- BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(u256(0)));
- BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(u256(0)));
- BOOST_CHECK(callContractFunction("addr(string)", encodeDyn(name)) == encodeArgs(u256(0)));
- BOOST_CHECK(callContractFunction("subRegistrar(string)", encodeDyn(name)) == encodeArgs(u256(0)));
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-}
-}
-} // end namespaces
diff --git a/libsolidity/SolidityWallet.cpp b/libsolidity/SolidityWallet.cpp
deleted file mode 100644
index 3c88afd9..00000000
--- a/libsolidity/SolidityWallet.cpp
+++ /dev/null
@@ -1,668 +0,0 @@
-/*
- This file is part of cpp-ethereum.
-
- cpp-ethereum is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- cpp-ethereum is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
-*/
-/**
- * @author Christian <c@ethdev.com>
- * @date 2015
- * Tests for a (comparatively) complex multisig wallet contract.
- */
-
-#include <string>
-#include <tuple>
-#include <boost/test/unit_test.hpp>
-#include <libdevcore/Hash.h>
-#include <test/libsolidity/solidityExecutionFramework.h>
-
-using namespace std;
-
-namespace dev
-{
-namespace solidity
-{
-namespace test
-{
-
-static char const* walletCode = R"DELIMITER(
-//sol Wallet
-// Multi-sig, daily-limited account proxy/wallet.
-// @authors:
-// Gav Wood <g@ethdev.com>
-// inheritable "property" contract that enables methods to be protected by requiring the acquiescence of either a
-// single, or, crucially, each of a number of, designated owners.
-// usage:
-// use modifiers onlyowner (just own owned) or onlymanyowners(hash), whereby the same hash must be provided by
-// some number (specified in constructor) of the set of owners (specified in the constructor, modifiable) before the
-// interior is executed.
-contract multiowned {
-
- // TYPES
-
- // struct for the status of a pending operation.
- struct PendingState {
- uint yetNeeded;
- uint ownersDone;
- uint index;
- }
-
- // EVENTS
-
- // this contract only has five types of events: it can accept a confirmation, in which case
- // we record owner and operation (hash) alongside it.
- event Confirmation(address owner, bytes32 operation);
- event Revoke(address owner, bytes32 operation);
- // some others are in the case of an owner changing.
- event OwnerChanged(address oldOwner, address newOwner);
- event OwnerAdded(address newOwner);
- event OwnerRemoved(address oldOwner);
- // the last one is emitted if the required signatures change
- event RequirementChanged(uint newRequirement);
-
- // MODIFIERS
-
- // simple single-sig function modifier.
- modifier onlyowner {
- if (isOwner(msg.sender))
- _
- }
- // multi-sig function modifier: the operation must have an intrinsic hash in order
- // that later attempts can be realised as the same underlying operation and
- // thus count as confirmations.
- modifier onlymanyowners(bytes32 _operation) {
- if (confirmAndCheck(_operation))
- _
- }
-
- // METHODS
-
- // constructor is given number of sigs required to do protected "onlymanyowners" transactions
- // as well as the selection of addresses capable of confirming them.
- function multiowned(address[] _owners, uint _required) {
- m_numOwners = _owners.length + 1;
- m_owners[1] = uint(msg.sender);
- m_ownerIndex[uint(msg.sender)] = 1;
- for (uint i = 0; i < _owners.length; ++i)
- {
- m_owners[2 + i] = uint(_owners[i]);
- m_ownerIndex[uint(_owners[i])] = 2 + i;
- }
- m_required = _required;
- }
-
- // Revokes a prior confirmation of the given operation
- function revoke(bytes32 _operation) external {
- uint ownerIndex = m_ownerIndex[uint(msg.sender)];
- // make sure they're an owner
- if (ownerIndex == 0) return;
- uint ownerIndexBit = 2**ownerIndex;
- var pending = m_pending[_operation];
- if (pending.ownersDone & ownerIndexBit > 0) {
- pending.yetNeeded++;
- pending.ownersDone -= ownerIndexBit;
- Revoke(msg.sender, _operation);
- }
- }
-
- // Replaces an owner `_from` with another `_to`.
- function changeOwner(address _from, address _to) onlymanyowners(sha3(msg.data)) external {
- if (isOwner(_to)) return;
- uint ownerIndex = m_ownerIndex[uint(_from)];
- if (ownerIndex == 0) return;
-
- clearPending();
- m_owners[ownerIndex] = uint(_to);
- m_ownerIndex[uint(_from)] = 0;
- m_ownerIndex[uint(_to)] = ownerIndex;
- OwnerChanged(_from, _to);
- }
-
- function addOwner(address _owner) onlymanyowners(sha3(msg.data)) external {
- if (isOwner(_owner)) return;
-
- clearPending();
- if (m_numOwners >= c_maxOwners)
- reorganizeOwners();
- if (m_numOwners >= c_maxOwners)
- return;
- m_numOwners++;
- m_owners[m_numOwners] = uint(_owner);
- m_ownerIndex[uint(_owner)] = m_numOwners;
- OwnerAdded(_owner);
- }
-
- function removeOwner(address _owner) onlymanyowners(sha3(msg.data)) external {
- uint ownerIndex = m_ownerIndex[uint(_owner)];
- if (ownerIndex == 0) return;
- if (m_required > m_numOwners - 1) return;
-
- m_owners[ownerIndex] = 0;
- m_ownerIndex[uint(_owner)] = 0;
- clearPending();
- reorganizeOwners(); //make sure m_numOwner is equal to the number of owners and always points to the optimal free slot
- OwnerRemoved(_owner);
- }
-
- function changeRequirement(uint _newRequired) onlymanyowners(sha3(msg.data)) external {
- if (_newRequired > m_numOwners) return;
- m_required = _newRequired;
- clearPending();
- RequirementChanged(_newRequired);
- }
-
- function isOwner(address _addr) returns (bool) {
- return m_ownerIndex[uint(_addr)] > 0;
- }
-
- function hasConfirmed(bytes32 _operation, address _owner) constant returns (bool) {
- var pending = m_pending[_operation];
- uint ownerIndex = m_ownerIndex[uint(_owner)];
-
- // make sure they're an owner
- if (ownerIndex == 0) return false;
-
- // determine the bit to set for this owner.
- uint ownerIndexBit = 2**ownerIndex;
- if (pending.ownersDone & ownerIndexBit == 0) {
- return false;
- } else {
- return true;
- }
- }
-
- // INTERNAL METHODS
-
- function confirmAndCheck(bytes32 _operation) internal returns (bool) {
- // determine what index the present sender is:
- uint ownerIndex = m_ownerIndex[uint(msg.sender)];
- // make sure they're an owner
- if (ownerIndex == 0) return;
-
- var pending = m_pending[_operation];
- // if we're not yet working on this operation, switch over and reset the confirmation status.
- if (pending.yetNeeded == 0) {
- // reset count of confirmations needed.
- pending.yetNeeded = m_required;
- // reset which owners have confirmed (none) - set our bitmap to 0.
- pending.ownersDone = 0;
- pending.index = m_pendingIndex.length++;
- m_pendingIndex[pending.index] = _operation;
- }
- // determine the bit to set for this owner.
- uint ownerIndexBit = 2**ownerIndex;
- // make sure we (the message sender) haven't confirmed this operation previously.
- if (pending.ownersDone & ownerIndexBit == 0) {
- Confirmation(msg.sender, _operation);
- // ok - check if count is enough to go ahead.
- if (pending.yetNeeded <= 1) {
- // enough confirmations: reset and run interior.
- delete m_pendingIndex[m_pending[_operation].index];
- delete m_pending[_operation];
- return true;
- }
- else
- {
- // not enough: record that this owner in particular confirmed.
- pending.yetNeeded--;
- pending.ownersDone |= ownerIndexBit;
- }
- }
- }
-
- function reorganizeOwners() private returns (bool) {
- uint free = 1;
- while (free < m_numOwners)
- {
- while (free < m_numOwners && m_owners[free] != 0) free++;
- while (m_numOwners > 1 && m_owners[m_numOwners] == 0) m_numOwners--;
- if (free < m_numOwners && m_owners[m_numOwners] != 0 && m_owners[free] == 0)
- {
- m_owners[free] = m_owners[m_numOwners];
- m_ownerIndex[m_owners[free]] = free;
- m_owners[m_numOwners] = 0;
- }
- }
- }
-
- function clearPending() internal {
- uint length = m_pendingIndex.length;
- for (uint i = 0; i < length; ++i)
- if (m_pendingIndex[i] != 0)
- delete m_pending[m_pendingIndex[i]];
- delete m_pendingIndex;
- }
-
- // FIELDS
-
- // the number of owners that must confirm the same operation before it is run.
- uint public m_required;
- // pointer used to find a free slot in m_owners
- uint public m_numOwners;
-
- // list of owners
- uint[256] m_owners;
- uint constant c_maxOwners = 250;
- // index on the list of owners to allow reverse lookup
- mapping(uint => uint) m_ownerIndex;
- // the ongoing operations.
- mapping(bytes32 => PendingState) m_pending;
- bytes32[] m_pendingIndex;
-}
-
-// inheritable "property" contract that enables methods to be protected by placing a linear limit (specifiable)
-// on a particular resource per calendar day. is multiowned to allow the limit to be altered. resource that method
-// uses is specified in the modifier.
-contract daylimit is multiowned {
-
- // MODIFIERS
-
- // simple modifier for daily limit.
- modifier limitedDaily(uint _value) {
- if (underLimit(_value))
- _
- }
-
- // METHODS
-
- // constructor - stores initial daily limit and records the present day's index.
- function daylimit(uint _limit) {
- m_dailyLimit = _limit;
- m_lastDay = today();
- }
- // (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today.
- function setDailyLimit(uint _newLimit) onlymanyowners(sha3(msg.data)) external {
- m_dailyLimit = _newLimit;
- }
- // (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today.
- function resetSpentToday() onlymanyowners(sha3(msg.data)) external {
- m_spentToday = 0;
- }
-
- // INTERNAL METHODS
-
- // checks to see if there is at least `_value` left from the daily limit today. if there is, subtracts it and
- // returns true. otherwise just returns false.
- function underLimit(uint _value) internal onlyowner returns (bool) {
- // reset the spend limit if we're on a different day to last time.
- if (today() > m_lastDay) {
- m_spentToday = 0;
- m_lastDay = today();
- }
- // check to see if there's enough left - if so, subtract and return true.
- if (m_spentToday + _value >= m_spentToday && m_spentToday + _value <= m_dailyLimit) {
- m_spentToday += _value;
- return true;
- }
- return false;
- }
- // determines today's index.
- function today() private constant returns (uint) { return now / 1 days; }
-
- // FIELDS
-
- uint public m_dailyLimit;
- uint m_spentToday;
- uint m_lastDay;
-}
-
-// interface contract for multisig proxy contracts; see below for docs.
-contract multisig {
-
- // EVENTS
-
- // logged events:
- // Funds has arrived into the wallet (record how much).
- event Deposit(address from, uint value);
- // Single transaction going out of the wallet (record who signed for it, how much, and to whom it's going).
- event SingleTransact(address owner, uint value, address to, bytes data);
- // Multi-sig transaction going out of the wallet (record who signed for it last, the operation hash, how much, and to whom it's going).
- event MultiTransact(address owner, bytes32 operation, uint value, address to, bytes data);
- // Confirmation still needed for a transaction.
- event ConfirmationNeeded(bytes32 operation, address initiator, uint value, address to, bytes data);
-
- // FUNCTIONS
-
- // TODO: document
- function changeOwner(address _from, address _to) external;
- function execute(address _to, uint _value, bytes _data) external returns (bytes32);
- function confirm(bytes32 _h) returns (bool);
-}
-
-// usage:
-// bytes32 h = Wallet(w).from(oneOwner).transact(to, value, data);
-// Wallet(w).from(anotherOwner).confirm(h);
-contract Wallet is multisig, multiowned, daylimit {
-
- // TYPES
-
- // Transaction structure to remember details of transaction lest it need be saved for a later call.
- struct Transaction {
- address to;
- uint value;
- bytes data;
- }
-
- // METHODS
-
- // constructor - just pass on the owner array to the multiowned and
- // the limit to daylimit
- function Wallet(address[] _owners, uint _required, uint _daylimit)
- multiowned(_owners, _required) daylimit(_daylimit) {
- }
-
- // kills the contract sending everything to `_to`.
- function kill(address _to) onlymanyowners(sha3(msg.data)) external {
- suicide(_to);
- }
-
- // gets called when no other function matches
- function() {
- // just being sent some cash?
- if (msg.value > 0)
- Deposit(msg.sender, msg.value);
- }
-
- // Outside-visible transact entry point. Executes transacion immediately if below daily spend limit.
- // If not, goes into multisig process. We provide a hash on return to allow the sender to provide
- // shortcuts for the other confirmations (allowing them to avoid replicating the _to, _value
- // and _data arguments). They still get the option of using them if they want, anyways.
- function execute(address _to, uint _value, bytes _data) external onlyowner returns (bytes32 _r) {
- // first, take the opportunity to check that we're under the daily limit.
- if (underLimit(_value)) {
- SingleTransact(msg.sender, _value, _to, _data);
- // yes - just execute the call.
- _to.call.value(_value)(_data);
- return 0;
- }
- // determine our operation hash.
- _r = sha3(msg.data, block.number);
- if (!confirm(_r) && m_txs[_r].to == 0) {
- m_txs[_r].to = _to;
- m_txs[_r].value = _value;
- m_txs[_r].data = _data;
- ConfirmationNeeded(_r, msg.sender, _value, _to, _data);
- }
- }
-
- // confirm a transaction through just the hash. we use the previous transactions map, m_txs, in order
- // to determine the body of the transaction from the hash provided.
- function confirm(bytes32 _h) onlymanyowners(_h) returns (bool) {
- if (m_txs[_h].to != 0) {
- m_txs[_h].to.call.value(m_txs[_h].value)(m_txs[_h].data);
- MultiTransact(msg.sender, _h, m_txs[_h].value, m_txs[_h].to, m_txs[_h].data);
- delete m_txs[_h];
- return true;
- }
- }
-
- // INTERNAL METHODS
-
- function clearPending() internal {
- uint length = m_pendingIndex.length;
- for (uint i = 0; i < length; ++i)
- delete m_txs[m_pendingIndex[i]];
- super.clearPending();
- }
-
- // FIELDS
-
- // pending transactions we have at present.
- mapping (bytes32 => Transaction) m_txs;
-}
-)DELIMITER";
-
-static unique_ptr<bytes> s_compiledWallet;
-
-class WalletTestFramework: public ExecutionFramework
-{
-protected:
- void deployWallet(
- u256 const& _value = 0,
- vector<u256> const& _owners = vector<u256>{},
- u256 _required = 1,
- u256 _dailyLimit = 0
- )
- {
- if (!s_compiledWallet)
- {
- m_optimize = true;
- m_compiler.reset(false, m_addStandardSources);
- m_compiler.addSource("", walletCode);
- ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize, m_optimizeRuns), "Compiling contract failed");
- s_compiledWallet.reset(new bytes(m_compiler.getBytecode("Wallet")));
- }
- bytes args = encodeArgs(u256(0x60), _required, _dailyLimit, u256(_owners.size()), _owners);
- sendMessage(*s_compiledWallet + args, true, _value);
- BOOST_REQUIRE(!m_output.empty());
- }
-};
-
-/// This is a test suite that tests optimised code!
-BOOST_FIXTURE_TEST_SUITE(SolidityWallet, WalletTestFramework)
-
-BOOST_AUTO_TEST_CASE(creation)
-{
- deployWallet(200);
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(m_sender, h256::AlignRight)) == encodeArgs(true));
- BOOST_REQUIRE(callContractFunction("isOwner(address)", ~h256(m_sender, h256::AlignRight)) == encodeArgs(false));
-}
-
-BOOST_AUTO_TEST_CASE(add_owners)
-{
- deployWallet(200);
- Address originalOwner = m_sender;
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12)) == encodeArgs(true));
- // now let the new owner add someone
- m_sender = Address(0x12);
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x13)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x13)) == encodeArgs(true));
- // and check that a non-owner cannot add a new owner
- m_sender = Address(0x50);
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x20)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x20)) == encodeArgs(false));
- // finally check that all the owners are there
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(originalOwner, h256::AlignRight)) == encodeArgs(true));
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12)) == encodeArgs(true));
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x13)) == encodeArgs(true));
-}
-
-BOOST_AUTO_TEST_CASE(change_owners)
-{
- deployWallet(200);
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12)) == encodeArgs(true));
- BOOST_REQUIRE(callContractFunction("changeOwner(address,address)", h256(0x12), h256(0x13)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12)) == encodeArgs(false));
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x13)) == encodeArgs(true));
-}
-
-BOOST_AUTO_TEST_CASE(remove_owner)
-{
- deployWallet(200);
- // add 10 owners
- for (unsigned i = 0; i < 10; ++i)
- {
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12 + i)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12 + i)) == encodeArgs(true));
- }
- // check they are there again
- for (unsigned i = 0; i < 10; ++i)
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12 + i)) == encodeArgs(true));
- // remove the odd owners
- for (unsigned i = 0; i < 10; ++i)
- if (i % 2 == 1)
- BOOST_REQUIRE(callContractFunction("removeOwner(address)", h256(0x12 + i)) == encodeArgs());
- // check the result
- for (unsigned i = 0; i < 10; ++i)
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12 + i)) == encodeArgs(i % 2 == 0));
- // add them again
- for (unsigned i = 0; i < 10; ++i)
- if (i % 2 == 1)
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12 + i)) == encodeArgs());
- // check everyone is there
- for (unsigned i = 0; i < 10; ++i)
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12 + i)) == encodeArgs(true));
-}
-
-BOOST_AUTO_TEST_CASE(initial_owners)
-{
- vector<u256> owners{
- u256("0x00000000000000000000000042c56279432962a17176998a4747d1b4d6ed4367"),
- u256("0x000000000000000000000000d4d4669f5ba9f4c27d38ef02a358c339b5560c47"),
- u256("0x000000000000000000000000e6716f9544a56c530d868e4bfbacb172315bdead"),
- u256("0x000000000000000000000000775e18be7a50a0abb8a4e82b1bd697d79f31fe04"),
- u256("0x000000000000000000000000f4dd5c3794f1fd0cdc0327a83aa472609c806e99"),
- u256("0x0000000000000000000000004c9113886af165b2de069d6e99430647e94a9fff"),
- u256("0x0000000000000000000000003fb1cd2cd96c6d5c0b5eb3322d807b34482481d4")
- };
- deployWallet(0, owners, 4, 2);
- BOOST_CHECK(callContractFunction("m_numOwners()") == encodeArgs(u256(8)));
- BOOST_CHECK(callContractFunction("isOwner(address)", h256(m_sender, h256::AlignRight)) == encodeArgs(true));
- for (u256 const& owner: owners)
- {
- BOOST_CHECK(callContractFunction("isOwner(address)", owner) == encodeArgs(true));
- }
-}
-
-BOOST_AUTO_TEST_CASE(multisig_value_transfer)
-{
- deployWallet(200);
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x13)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x14)) == encodeArgs());
- // 4 owners, set required to 3
- BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs());
- // check that balance is and stays zero at destination address
- h256 opHash("8f27f478ebcfaf28b0c354f4809ace8087000d668b89c8bc3b1b608bfdbe6654");
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- m_sender = Address(0x12);
- BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- m_sender = Address(0x13);
- BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- m_sender = Address(0x14);
- BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));
- // now it should go through
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 100);
-}
-
-BOOST_AUTO_TEST_CASE(revoke_addOwner)
-{
- deployWallet();
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x13)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x14)) == encodeArgs());
- // 4 owners, set required to 3
- BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs());
- // add a new owner
- Address deployer = m_sender;
- h256 opHash = sha3(FixedHash<4>(dev::sha3("addOwner(address)")).asBytes() + h256(0x33).asBytes());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x33)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x33)) == encodeArgs(false));
- m_sender = Address(0x12);
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x33)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x33)) == encodeArgs(false));
- // revoke one confirmation
- m_sender = deployer;
- BOOST_REQUIRE(callContractFunction("revoke(bytes32)", opHash) == encodeArgs());
- m_sender = Address(0x13);
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x33)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x33)) == encodeArgs(false));
- m_sender = Address(0x14);
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x33)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x33)) == encodeArgs(true));
-}
-
-BOOST_AUTO_TEST_CASE(revoke_transaction)
-{
- deployWallet(200);
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x13)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x14)) == encodeArgs());
- // 4 owners, set required to 3
- BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs());
- // create a transaction
- Address deployer = m_sender;
- h256 opHash("8f27f478ebcfaf28b0c354f4809ace8087000d668b89c8bc3b1b608bfdbe6654");
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- m_sender = Address(0x12);
- BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- m_sender = Address(0x13);
- BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- m_sender = Address(0x12);
- BOOST_REQUIRE(callContractFunction("revoke(bytes32)", opHash) == encodeArgs());
- m_sender = deployer;
- BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- m_sender = Address(0x14);
- BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));
- // now it should go through
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 100);
-}
-
-BOOST_AUTO_TEST_CASE(daylimit)
-{
- deployWallet(200);
- BOOST_REQUIRE(callContractFunction("m_dailyLimit()") == encodeArgs(u256(0)));
- BOOST_REQUIRE(callContractFunction("setDailyLimit(uint256)", h256(100)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("m_dailyLimit()") == encodeArgs(u256(100)));
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x13)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x14)) == encodeArgs());
- // 4 owners, set required to 3
- BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs());
-
- // try to send tx over daylimit
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- m_sender = Address(0x12);
- BOOST_REQUIRE(
- callContractFunction("execute(address,uint256,bytes)", h256(0x05), 150, 0x60, 0x00) !=
- encodeArgs(u256(0))
- );
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- // try to send tx under daylimit by stranger
- m_sender = Address(0x77);
- BOOST_REQUIRE(
- callContractFunction("execute(address,uint256,bytes)", h256(0x05), 90, 0x60, 0x00) ==
- encodeArgs(u256(0))
- );
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- // now send below limit by owner
- m_sender = Address(0x12);
- BOOST_REQUIRE(
- callContractFunction("execute(address,uint256,bytes)", h256(0x05), 90, 0x60, 0x00) ==
- encodeArgs(u256(0))
- );
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 90);
-}
-
-BOOST_AUTO_TEST_CASE(daylimit_constructor)
-{
- deployWallet(200, {}, 1, 20);
- BOOST_REQUIRE(callContractFunction("m_dailyLimit()") == encodeArgs(u256(20)));
- BOOST_REQUIRE(callContractFunction("setDailyLimit(uint256)", h256(30)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("m_dailyLimit()") == encodeArgs(u256(30)));
-}
-
-//@todo test data calls
-
-BOOST_AUTO_TEST_SUITE_END()
-
-}
-}
-} // end namespaces