mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #11426 from ethereum/test-fixedfee
Move contracts/FixedFeeRegistrar to semanticTests/externalContracts
This commit is contained in:
commit
614683019b
@ -24,7 +24,6 @@ detect_stray_source_files("${sources}" ".")
|
|||||||
set(contracts_sources
|
set(contracts_sources
|
||||||
contracts/AuctionRegistrar.cpp
|
contracts/AuctionRegistrar.cpp
|
||||||
contracts/ContractInterface.h
|
contracts/ContractInterface.h
|
||||||
contracts/FixedFeeRegistrar.cpp
|
|
||||||
contracts/Wallet.cpp
|
contracts/Wallet.cpp
|
||||||
)
|
)
|
||||||
detect_stray_source_files("${contracts_sources}" "contracts/")
|
detect_stray_source_files("${contracts_sources}" "contracts/")
|
||||||
|
@ -1,255 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of solidity.
|
|
||||||
|
|
||||||
solidity 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.
|
|
||||||
|
|
||||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
/**
|
|
||||||
* @author Christian <c@ethdev.com>
|
|
||||||
* @date 2015
|
|
||||||
* Tests for a fixed fee registrar contract.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <libsolutil/LazyInit.h>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <tuple>
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#pragma warning(push)
|
|
||||||
#pragma warning(disable:4535) // calling _set_se_translator requires /EHa
|
|
||||||
#endif
|
|
||||||
#include <boost/test/unit_test.hpp>
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#pragma warning(pop)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <test/libsolidity/SolidityExecutionFramework.h>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace solidity;
|
|
||||||
using namespace solidity::util;
|
|
||||||
using namespace solidity::test;
|
|
||||||
|
|
||||||
namespace solidity::frontend::test
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
static char const* registrarCode = R"DELIMITER(
|
|
||||||
//sol FixedFeeRegistrar
|
|
||||||
// Simple global registrar with fixed-fee reservations.
|
|
||||||
// @authors:
|
|
||||||
// Gav Wood <g@ethdev.com>
|
|
||||||
|
|
||||||
pragma solidity >=0.4.0 <0.9.0;
|
|
||||||
|
|
||||||
abstract contract Registrar {
|
|
||||||
event Changed(string indexed name);
|
|
||||||
|
|
||||||
function owner(string memory _name) public virtual view returns (address o_owner);
|
|
||||||
function addr(string memory _name) public virtual view returns (address o_address);
|
|
||||||
function subRegistrar(string memory _name) virtual public view returns (address o_subRegistrar);
|
|
||||||
function content(string memory _name) public virtual view returns (bytes32 o_content);
|
|
||||||
}
|
|
||||||
|
|
||||||
contract FixedFeeRegistrar is Registrar {
|
|
||||||
struct Record {
|
|
||||||
address addr;
|
|
||||||
address subRegistrar;
|
|
||||||
bytes32 content;
|
|
||||||
address owner;
|
|
||||||
}
|
|
||||||
|
|
||||||
modifier onlyrecordowner(string memory _name) { if (m_record(_name).owner == msg.sender) _; }
|
|
||||||
|
|
||||||
function reserve(string memory _name) public payable {
|
|
||||||
Record storage rec = m_record(_name);
|
|
||||||
if (rec.owner == 0x0000000000000000000000000000000000000000 && msg.value >= c_fee) {
|
|
||||||
rec.owner = msg.sender;
|
|
||||||
emit Changed(_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function disown(string memory _name, address payable _refund) onlyrecordowner(_name) public {
|
|
||||||
delete m_recordData[uint(keccak256(bytes(_name))) / 8];
|
|
||||||
if (!_refund.send(c_fee))
|
|
||||||
revert();
|
|
||||||
emit Changed(_name);
|
|
||||||
}
|
|
||||||
function transfer(string memory _name, address _newOwner) onlyrecordowner(_name) public {
|
|
||||||
m_record(_name).owner = _newOwner;
|
|
||||||
emit Changed(_name);
|
|
||||||
}
|
|
||||||
function setAddr(string memory _name, address _a) onlyrecordowner(_name) public {
|
|
||||||
m_record(_name).addr = _a;
|
|
||||||
emit Changed(_name);
|
|
||||||
}
|
|
||||||
function setSubRegistrar(string memory _name, address _registrar) onlyrecordowner(_name) public {
|
|
||||||
m_record(_name).subRegistrar = _registrar;
|
|
||||||
emit Changed(_name);
|
|
||||||
}
|
|
||||||
function setContent(string memory _name, bytes32 _content) onlyrecordowner(_name) public {
|
|
||||||
m_record(_name).content = _content;
|
|
||||||
emit Changed(_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
function record(string memory _name) public view returns (address o_addr, address o_subRegistrar, bytes32 o_content, address o_owner) {
|
|
||||||
Record storage rec = m_record(_name);
|
|
||||||
o_addr = rec.addr;
|
|
||||||
o_subRegistrar = rec.subRegistrar;
|
|
||||||
o_content = rec.content;
|
|
||||||
o_owner = rec.owner;
|
|
||||||
}
|
|
||||||
function addr(string memory _name) public override view returns (address) { return m_record(_name).addr; }
|
|
||||||
function subRegistrar(string memory _name) public override view returns (address) { return m_record(_name).subRegistrar; }
|
|
||||||
function content(string memory _name) public override view returns (bytes32) { return m_record(_name).content; }
|
|
||||||
function owner(string memory _name) public override view returns (address) { return m_record(_name).owner; }
|
|
||||||
|
|
||||||
Record[2**253] m_recordData;
|
|
||||||
function m_record(string memory _name) view internal returns (Record storage o_record) {
|
|
||||||
return m_recordData[uint(keccak256(bytes(_name))) / 8];
|
|
||||||
}
|
|
||||||
uint constant c_fee = 69 ether;
|
|
||||||
}
|
|
||||||
)DELIMITER";
|
|
||||||
|
|
||||||
static LazyInit<bytes> s_compiledRegistrar;
|
|
||||||
|
|
||||||
class RegistrarTestFramework: public SolidityExecutionFramework
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
void deployRegistrar()
|
|
||||||
{
|
|
||||||
bytes const& compiled = s_compiledRegistrar.init([&]{
|
|
||||||
return compileContract(registrarCode, "FixedFeeRegistrar");
|
|
||||||
});
|
|
||||||
|
|
||||||
sendMessage(compiled, true);
|
|
||||||
BOOST_REQUIRE(m_transactionSuccessful);
|
|
||||||
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"};
|
|
||||||
BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name[0])) == encodeArgs());
|
|
||||||
BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[0])) == encodeArgs(account(0)));
|
|
||||||
BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee + 1, encodeDyn(name[1])) == encodeArgs());
|
|
||||||
BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[1])) == encodeArgs(account(0)));
|
|
||||||
BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee - 1, encodeDyn(name[2])) == encodeArgs());
|
|
||||||
BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[2])) == encodeArgs(h160{}));
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(double_reserve)
|
|
||||||
{
|
|
||||||
// Test that it is not possible to re-reserve from a different address.
|
|
||||||
deployRegistrar();
|
|
||||||
string name = "abc";
|
|
||||||
BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
|
|
||||||
BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(account(0)));
|
|
||||||
|
|
||||||
sendEther(account(1), 100 * ether);
|
|
||||||
m_sender = account(1);
|
|
||||||
BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
|
|
||||||
BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(account(0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(properties)
|
|
||||||
{
|
|
||||||
// Test setting and retrieving the various properties works.
|
|
||||||
deployRegistrar();
|
|
||||||
string names[] = {"abc", "def", "ghi"};
|
|
||||||
size_t addr = 0x9872543;
|
|
||||||
size_t count = 1;
|
|
||||||
for (string const& name: names)
|
|
||||||
{
|
|
||||||
addr++;
|
|
||||||
m_sender = account(0);
|
|
||||||
sendEther(account(count), 100 * ether);
|
|
||||||
m_sender = account(count);
|
|
||||||
h160 owner = m_sender;
|
|
||||||
// setting by sender works
|
|
||||||
BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
|
|
||||||
BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(owner));
|
|
||||||
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));
|
|
||||||
count++;
|
|
||||||
// but not by someone else
|
|
||||||
m_sender = account(0);
|
|
||||||
sendEther(account(count), 100 * ether);
|
|
||||||
m_sender = account(count);
|
|
||||||
BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(owner));
|
|
||||||
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));
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(transfer)
|
|
||||||
{
|
|
||||||
deployRegistrar();
|
|
||||||
string name = "abc";
|
|
||||||
BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
|
|
||||||
BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), account(0), 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(account(0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(disown)
|
|
||||||
{
|
|
||||||
deployRegistrar();
|
|
||||||
string name = "abc";
|
|
||||||
BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
|
|
||||||
BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), account(0), 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(balanceAt(h160(0x124)), 0);
|
|
||||||
BOOST_CHECK(callContractFunction("disown(string,address)", u256(0x40), u256(0x124), name.size(), name) == encodeArgs());
|
|
||||||
BOOST_CHECK_EQUAL(balanceAt(h160(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
|
|
@ -0,0 +1,111 @@
|
|||||||
|
//sol FixedFeeRegistrar
|
||||||
|
// Simple global registrar with fixed-fee reservations.
|
||||||
|
// @authors:
|
||||||
|
// Gav Wood <g@ethdev.com>
|
||||||
|
|
||||||
|
pragma solidity >=0.4.0 <0.9.0;
|
||||||
|
|
||||||
|
abstract contract Registrar {
|
||||||
|
event Changed(string indexed name);
|
||||||
|
|
||||||
|
function owner(string memory _name) public virtual view returns (address o_owner);
|
||||||
|
function addr(string memory _name) public virtual view returns (address o_address);
|
||||||
|
function subRegistrar(string memory _name) virtual public view returns (address o_subRegistrar);
|
||||||
|
function content(string memory _name) public virtual view returns (bytes32 o_content);
|
||||||
|
}
|
||||||
|
|
||||||
|
contract FixedFeeRegistrar is Registrar {
|
||||||
|
struct Record {
|
||||||
|
address addr;
|
||||||
|
address subRegistrar;
|
||||||
|
bytes32 content;
|
||||||
|
address owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier onlyrecordowner(string memory _name) { if (m_record(_name).owner == msg.sender) _; }
|
||||||
|
|
||||||
|
function reserve(string memory _name) public payable {
|
||||||
|
Record storage rec = m_record(_name);
|
||||||
|
if (rec.owner == 0x0000000000000000000000000000000000000000 && msg.value >= c_fee) {
|
||||||
|
rec.owner = msg.sender;
|
||||||
|
emit Changed(_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function disown(string memory _name, address payable _refund) onlyrecordowner(_name) public {
|
||||||
|
delete m_recordData[uint(keccak256(bytes(_name))) / 8];
|
||||||
|
if (!_refund.send(c_fee))
|
||||||
|
revert();
|
||||||
|
emit Changed(_name);
|
||||||
|
}
|
||||||
|
function transfer(string memory _name, address _newOwner) onlyrecordowner(_name) public {
|
||||||
|
m_record(_name).owner = _newOwner;
|
||||||
|
emit Changed(_name);
|
||||||
|
}
|
||||||
|
function setAddr(string memory _name, address _a) onlyrecordowner(_name) public {
|
||||||
|
m_record(_name).addr = _a;
|
||||||
|
emit Changed(_name);
|
||||||
|
}
|
||||||
|
function setSubRegistrar(string memory _name, address _registrar) onlyrecordowner(_name) public {
|
||||||
|
m_record(_name).subRegistrar = _registrar;
|
||||||
|
emit Changed(_name);
|
||||||
|
}
|
||||||
|
function setContent(string memory _name, bytes32 _content) onlyrecordowner(_name) public {
|
||||||
|
m_record(_name).content = _content;
|
||||||
|
emit Changed(_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function record(string memory _name) public view returns (address o_addr, address o_subRegistrar, bytes32 o_content, address o_owner) {
|
||||||
|
Record storage rec = m_record(_name);
|
||||||
|
o_addr = rec.addr;
|
||||||
|
o_subRegistrar = rec.subRegistrar;
|
||||||
|
o_content = rec.content;
|
||||||
|
o_owner = rec.owner;
|
||||||
|
}
|
||||||
|
function addr(string memory _name) public override view returns (address) { return m_record(_name).addr; }
|
||||||
|
function subRegistrar(string memory _name) public override view returns (address) { return m_record(_name).subRegistrar; }
|
||||||
|
function content(string memory _name) public override view returns (bytes32) { return m_record(_name).content; }
|
||||||
|
function owner(string memory _name) public override view returns (address) { return m_record(_name).owner; }
|
||||||
|
|
||||||
|
Record[2**253] m_recordData;
|
||||||
|
function m_record(string memory _name) view internal returns (Record storage o_record) {
|
||||||
|
return m_recordData[uint(keccak256(bytes(_name))) / 8];
|
||||||
|
}
|
||||||
|
uint constant c_fee = 69 ether;
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// constructor()
|
||||||
|
// gas irOptimized: 544916
|
||||||
|
// gas legacy: 942808
|
||||||
|
// gas legacyOptimized: 492291
|
||||||
|
// reserve(string), 69 ether: 0x20, 3, "abc" ->
|
||||||
|
// gas irOptimized: 45527
|
||||||
|
// gas legacy: 46242
|
||||||
|
// gas legacyOptimized: 45491
|
||||||
|
// owner(string): 0x20, 3, "abc" -> 0x1212121212121212121212121212120000000012
|
||||||
|
// reserve(string), 70 ether: 0x20, 3, "def" ->
|
||||||
|
// owner(string): 0x20, 3, "def" -> 0x1212121212121212121212121212120000000012
|
||||||
|
// reserve(string), 68 ether: 0x20, 3, "ghi" ->
|
||||||
|
// owner(string): 0x20, 3, "ghi" -> 0
|
||||||
|
// account: 1 -> 0x1212121212121212121212121212120000001012
|
||||||
|
// reserve(string), 69 ether: 0x20, 3, "abc" ->
|
||||||
|
// owner(string): 0x20, 3, "abc" -> 0x1212121212121212121212121212120000000012
|
||||||
|
// account: 0 -> 0x1212121212121212121212121212120000000012
|
||||||
|
// setContent(string,bytes32): 0x40, 0, 3, "abc" ->
|
||||||
|
// transfer(string,address): 0x40, 555, 3, "abc" ->
|
||||||
|
// owner(string): 0x20, 3, "abc" -> 555
|
||||||
|
// content(string): 0x20, 3, "abc" -> 0x00
|
||||||
|
// setContent(string,bytes32): 0x40, 333, 3, "def" ->
|
||||||
|
// setAddr(string,address): 0x40, 124, 3, "def" ->
|
||||||
|
// setSubRegistrar(string,address): 0x40, 125, 3, "def" ->
|
||||||
|
// content(string): 0x20, 3, "def" -> 333
|
||||||
|
// addr(string): 0x20, 3, "def" -> 124
|
||||||
|
// subRegistrar(string): 0x20, 3, "def" -> 125
|
||||||
|
// balance: 0x124 -> 0
|
||||||
|
// disown(string,address): 0x40, 0x124, 3, "def" ->
|
||||||
|
// balance: 0x124 -> 0
|
||||||
|
// owner(string): 0x20, 3, "def" -> 0
|
||||||
|
// content(string): 0x20, 3, "def" -> 0
|
||||||
|
// addr(string): 0x20, 3, "def" -> 0
|
||||||
|
// subRegistrar(string): 0x20, 3, "def" -> 0
|
Loading…
Reference in New Issue
Block a user