From fb9ca8521699db7efc57822373dbd43b895dd35e Mon Sep 17 00:00:00 2001 From: Dimitry Khokhlov Date: Tue, 30 Jun 2015 22:35:55 +0400 Subject: [PATCH 01/19] FuzzTest: a few more random code From 086fe8188669ff4cf01bab1b86bdc7e225264e9d Mon Sep 17 00:00:00 2001 From: Dimitry Khokhlov Date: Wed, 1 Jul 2015 13:41:55 +0400 Subject: [PATCH 02/19] FuzzTests: More Smart Codes From b11cfb3d5105d48fe77e4896a4c5cb7e4064893e Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 2 Jul 2015 19:58:37 +0200 Subject: [PATCH 03/19] add badStateRootTest From 12422f0251d890b469bd9b727cbb079747ce9845 Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 3 Jul 2015 06:16:47 -0400 Subject: [PATCH 04/19] Sign, recovery, and verify. --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 952b1674f..cbf184808 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,7 @@ add_executable(testeth ${SRC_LIST} ${HEADERS}) target_link_libraries(testeth ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) target_link_libraries(testeth ${CURL_LIBRARIES}) +target_link_libraries(testeth ${CRYPTOPP_LIBRARIES}) target_link_libraries(testeth ethereum) target_link_libraries(testeth ethcore) if (NOT WIN32) From 953e392ad272042acd9f713434ad3f6a43cf4b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 3 Jul 2015 14:04:04 +0200 Subject: [PATCH 05/19] --vm command line option replacing --jit. --- TestHelper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TestHelper.cpp b/TestHelper.cpp index 698f35122..01bb5f300 100644 --- a/TestHelper.cpp +++ b/TestHelper.cpp @@ -235,7 +235,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state) } void ImportTest::importTransaction(json_spirit::mObject& _o) -{ +{ if (_o.count("secretKey") > 0) { assert(_o.count("nonce") > 0); @@ -728,7 +728,7 @@ Options::Options() for (auto i = 0; i < argc; ++i) { auto arg = std::string{argv[i]}; - if (arg == "--jit") + if (arg == "--jit" || arg == "--vm=jit") // TODO: Remove deprecated option "--jit" eth::VMFactory::setKind(eth::VMKind::JIT); else if (arg == "--vm=smart") eth::VMFactory::setKind(eth::VMKind::Smart); From 964422fa0bdf8c5f59dcb52f20cbbc1c25872761 Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 3 Jul 2015 08:52:46 -0400 Subject: [PATCH 06/19] fix failing peer test. From 09f0e7f6445a319c391c5cf50e9b3536a766603a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 3 Jul 2015 15:16:51 +0200 Subject: [PATCH 07/19] Make --vm command line option syntax consistent with other options. --- TestHelper.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/TestHelper.cpp b/TestHelper.cpp index 01bb5f300..b3dee72ec 100644 --- a/TestHelper.cpp +++ b/TestHelper.cpp @@ -728,10 +728,20 @@ Options::Options() for (auto i = 0; i < argc; ++i) { auto arg = std::string{argv[i]}; - if (arg == "--jit" || arg == "--vm=jit") // TODO: Remove deprecated option "--jit" - eth::VMFactory::setKind(eth::VMKind::JIT); - else if (arg == "--vm=smart") - eth::VMFactory::setKind(eth::VMKind::Smart); + if (arg == "--vm" && i + 1 < argc) + { + string vmKind = argv[++i]; + if (vmKind == "interpreter") + VMFactory::setKind(VMKind::Interpreter); + else if (vmKind == "jit") + VMFactory::setKind(VMKind::JIT); + else if (vmKind == "smart") + VMFactory::setKind(VMKind::Smart); + else + cerr << "Unknown VM kind: " << vmKind << endl; + } + else if (arg == "--jit") // TODO: Remove deprecated option "--jit" + VMFactory::setKind(VMKind::JIT); else if (arg == "--vmtrace") vmtrace = true; else if (arg == "--filltests") From 155ca7c1822eacd2a97afd8663bf23af0e468cde Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Thu, 2 Jul 2015 22:21:37 +0200 Subject: [PATCH 08/19] intermediate From 909e0bd1f6b10d61848d77a4221f2581bd4977ee Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Fri, 3 Jul 2015 01:14:56 +0200 Subject: [PATCH 09/19] proof of work bugfix From d18794ba3cedb9f9914e8759b4ec8b662b0ca4da Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Fri, 3 Jul 2015 16:33:36 +0200 Subject: [PATCH 10/19] another test introduced From 279b1d38fa87908d00e6ce6028fabbb5dd34e653 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Sat, 4 Jul 2015 01:09:31 +0200 Subject: [PATCH 11/19] rating initial version complete From f594f6c1dfe1fd88301c5d7372dd71d9ab3a4f22 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 3 Jul 2015 16:10:47 +0200 Subject: [PATCH 12/19] prioritized transaction queue Conflicts: libethereum/TransactionQueue.cpp msvc build fix From 67fed8aa250678be137d402c161445c6c1c8d920 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 5 Jul 2015 14:08:54 -0400 Subject: [PATCH 13/19] test for new transaction queue. Some cleanups and enhacements to Guards & Notifier. Fix an invariant TransactionQueue. From 130a7b9667c0808e5f4b621d720e2bc6c8ad7b9b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 5 Jul 2015 13:10:46 -0400 Subject: [PATCH 14/19] Revert "Txqueueasyncverify" From 7118c61723cdfb30927ddc9db2b3ec47d8b443d5 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 5 Jul 2015 22:11:40 +0200 Subject: [PATCH 15/19] import transactions in a separate thread From befbeba512701bbed29dc3cf7e630789d0600822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 6 Jul 2015 09:22:09 +0200 Subject: [PATCH 16/19] Fix up rvalue references. Avoid a copy of an EVM code in ExtVM. --- TestHelper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TestHelper.cpp b/TestHelper.cpp index b3dee72ec..9a1b16935 100644 --- a/TestHelper.cpp +++ b/TestHelper.cpp @@ -199,10 +199,10 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state, stateOptio stateOptions.m_bHasCode = true; } - if (code.size()) + if (!code.empty()) { _state.m_cache[address] = Account(balance, Account::ContractConception); - _state.m_cache[address].setCode(code); + _state.m_cache[address].setCode(std::move(code)); } else _state.m_cache[address] = Account(balance, Account::NormalCreation); From edddf61d39b0186120a4d5e836c02a0a53353118 Mon Sep 17 00:00:00 2001 From: Dimitry Khokhlov Date: Mon, 6 Jul 2015 18:14:39 +0400 Subject: [PATCH 17/19] stPreCompiledContracts remove as there is no 'out' when calling contracts from transaction From 438455da853bb081466094d69a3712c4eb301190 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 6 Jul 2015 15:23:11 +0200 Subject: [PATCH 18/19] Some initial tests for libdevcore/FixedHash From c5984302fcc33b032001a89ae636c6b956f72350 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 6 Jul 2015 18:04:26 +0200 Subject: [PATCH 19/19] Updated wallet code. --- libsolidity/SolidityWallet.cpp | 274 +++++++++++++++++++++------------ 1 file changed, 173 insertions(+), 101 deletions(-) diff --git a/libsolidity/SolidityWallet.cpp b/libsolidity/SolidityWallet.cpp index ba8f198f8..1c296b9f7 100644 --- a/libsolidity/SolidityWallet.cpp +++ b/libsolidity/SolidityWallet.cpp @@ -47,12 +47,18 @@ static char const* walletCode = R"DELIMITER( // 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); @@ -63,14 +69,9 @@ contract multiowned { event OwnerRemoved(address oldOwner); // the last one is emitted if the required signatures change event RequirementChanged(uint newRequirement); - // 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() { - m_required = 1; - m_numOwners = 1; - m_owners[m_numOwners] = uint(msg.sender); - m_ownerIndex[uint(msg.sender)] = m_numOwners; - } + + // MODIFIERS + // simple single-sig function modifier. modifier onlyowner { if (isOwner(msg.sender)) @@ -80,9 +81,21 @@ contract multiowned { // that later attempts can be realised as the same underlying operation and // thus count as confirmations. modifier onlymanyowners(bytes32 _operation) { - if (confirmed(_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() { + m_required = 1; + m_numOwners = 1; + m_owners[m_numOwners] = uint(msg.sender); + m_ownerIndex[uint(msg.sender)] = m_numOwners; + } + // Revokes a prior confirmation of the given operation function revoke(bytes32 _operation) external { uint ownerIndex = m_ownerIndex[uint(msg.sender)]; @@ -96,7 +109,75 @@ contract multiowned { Revoke(msg.sender, _operation); } } - function confirmed(bytes32 _operation) internal returns (bool) { + + // Replaces an owner `_from` with another `_to`. + function changeOwner(address _from, address _to) onlymanyowners(sha3(msg.data, block.number)) 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, block.number)) 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, block.number)) 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, block.number)) 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 @@ -132,42 +213,7 @@ contract multiowned { } } } - // 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 reorganizeOwners() private returns (bool) { uint free = 1; while (free < m_numOwners) @@ -182,6 +228,7 @@ contract multiowned { } } } + function clearPending() internal { uint length = m_pendingIndex.length; for (uint i = 0; i < length; ++i) @@ -189,46 +236,54 @@ contract multiowned { delete m_pending[m_pendingIndex[i]]; delete m_pendingIndex; } - 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; - } + + // 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] public m_owners; + uint[256] m_owners; uint constant c_maxOwners = 250; // index on the list of owners to allow reverse lookup - mapping(uint => uint) public m_ownerIndex; + mapping(uint => uint) m_ownerIndex; // the ongoing operations. - mapping(bytes32 => PendingState) public m_pending; - bytes32[] public m_pendingIndex; + 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 - just records the present day's index. function daylimit() { 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 { + function setDailyLimit(uint _newLimit) onlymanyowners(sha3(msg.data, block.number)) 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 { + function resetSpentToday() onlymanyowners(sha3(msg.data, block.number)) 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) { @@ -244,60 +299,76 @@ contract daylimit is multiowned { } return false; } - // simple modifier for daily limit. - modifier limitedDaily(uint _value) { - if (underLimit(_value)) - _ - } // determines today's index. function today() private constant returns (uint) { return now / 1 days; } - uint public m_spentToday; + + // FIELDS + uint public m_dailyLimit; - uint public m_lastDay; + uint m_spentToday; + uint m_lastDay; } + // interface contract for multisig proxy contracts; see below for docs. contract multisig { - event Deposit(address from, uint value); - event SingleTransact(address owner, uint value, address to, bytes data); - event MultiTransact(address owner, bytes32 operation, uint value, address to, bytes data); - event ConfirmationNeeded(bytes32 operation, address initiator, uint value, address to, bytes data); - 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 { - // Transaction structure to remember details of transaction lest it need be saved for a later call. - struct Transaction { - address to; - uint value; - bytes data; - } - /* + + // 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);*/ - // constructor - just pass on the owner arra to the multiowned. - event Created(); - function Wallet() { - Created(); + 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; } + + // EVENTS + + event Created(bytes32 indexed identifier); + + // METHODS + + // constructor - just pass on the owner arra to the multiowned. + function Wallet(bytes32 identifier) { + Created(identifier); + } + // kills the contract sending everything to `_to`. - function kill(address _to) onlymanyowners(sha3(msg.data)) external { + function kill(address _to) onlymanyowners(sha3(msg.data, block.number)) 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 @@ -311,7 +382,7 @@ contract Wallet is multisig, multiowned, daylimit { return 0; } // determine our operation hash. - _r = sha3(msg.data); + _r = sha3(msg.data, block.number); if (!confirm(_r) && m_txs[_r].to == 0) { m_txs[_r].to = _to; m_txs[_r].value = _value; @@ -319,6 +390,7 @@ contract Wallet is multisig, multiowned, daylimit { 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) { @@ -329,20 +401,20 @@ contract Wallet is multisig, multiowned, daylimit { 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(); } - // // internally confirm transaction with all of the info. returns true iff confirmed good and executed. - // function confirmVerbose(bytes32 _h, address _to, uint _value, bytes _data) private onlymanyowners(_h) returns (bool) { - // _to.call.value(_value)(_data); - // MultiTransact("out", msg.sender, _h, _value, _to); - // return true; - // } + + // FIELDS + // pending transactions we have at present. - mapping (bytes32 => Transaction) public m_txs; + mapping (bytes32 => Transaction) m_txs; } )DELIMITER"; @@ -443,7 +515,7 @@ BOOST_AUTO_TEST_CASE(multisig_value_transfer) // 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("f916231db11c12e0142dc51f23632bc655de87c63f83fc928c443e90f7aa364a"); + 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));