Skip to content
This repository has been archived by the owner on Oct 28, 2021. It is now read-only.

Commit

Permalink
WIP EIP198: Custom cost function for modexp contract
Browse files Browse the repository at this point in the history
  • Loading branch information
gumb0 committed Apr 3, 2017
1 parent 18773f8 commit 3892679
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 10 deletions.
4 changes: 2 additions & 2 deletions libethcore/ChainOperationParams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ PrecompiledContract::PrecompiledContract(
PrecompiledExecutor const& _exec,
u256 const& _startingBlock
):
PrecompiledContract([=](unsigned size) -> bigint
PrecompiledContract([=](bytesConstRef _in) -> bigint
{
bigint s = size;
bigint s = _in.size();
bigint b = _base;
bigint w = _word;
return b + (s + 31) / 32 * w;
Expand Down
6 changes: 3 additions & 3 deletions libethcore/ChainOperationParams.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class PrecompiledContract
public:
PrecompiledContract() = default;
PrecompiledContract(
std::function<bigint(size_t)> const& _cost,
PrecompiledPricer const& _cost,
PrecompiledExecutor const& _exec,
u256 const& _startingBlock = 0
):
Expand All @@ -52,13 +52,13 @@ class PrecompiledContract
u256 const& _startingBlock = 0
);

bigint cost(bytesConstRef _in) const { return m_cost(_in.size()); }
bigint cost(bytesConstRef _in) const { return m_cost(_in); }
std::pair<bool, bytes> execute(bytesConstRef _in) const { return m_execute(_in); }

u256 const& startingBlock() const { return m_startingBlock; }

private:
std::function<bigint(size_t)> m_cost;
PrecompiledPricer m_cost;
PrecompiledExecutor m_execute;
u256 m_startingBlock = 0;
};
Expand Down
11 changes: 11 additions & 0 deletions libethcore/Precompiled.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,15 @@ ETH_REGISTER_PRECOMPILED(modexp)(bytesConstRef _in)
return {true, ret};
}

ETH_REGISTER_PRECOMPILED_PRICER(modexp)(bytesConstRef _in)
{
size_t const baseLength(parseBigEndianRightPadded<u256>(_in, 0, 32));
size_t const expLength(parseBigEndianRightPadded<u256>(_in, 32, 32));
size_t const modLength(parseBigEndianRightPadded<u256>(_in, 64, 32));

size_t maxLength = max(modLength, baseLength);

return maxLength * maxLength * max(expLength, 1ULL) / 20;
}

}
20 changes: 16 additions & 4 deletions libethcore/Precompiled.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ namespace eth
{

using PrecompiledExecutor = std::function<std::pair<bool, bytes>(bytesConstRef _in)>;
using PrecompiledPricer = std::function<bigint(bytesConstRef _in)>;

DEV_SIMPLE_EXCEPTION(ExecutorNotFound);

Expand All @@ -41,20 +42,31 @@ class PrecompiledRegistrar
/// Get the executor object for @a _name function or @throw ExecutorNotFound if not found.
static PrecompiledExecutor const& executor(std::string const& _name);

/// Get the price calculator object for @a _name function or @throw ExecutorNotFound if not found.
static PrecompiledPricer const& pricer(std::string const& _name);

/// Register an executor. In general just use ETH_REGISTER_PRECOMPILED.
static PrecompiledExecutor registerPrecompiled(std::string const& _name, PrecompiledExecutor const& _exec) { return (get()->m_execs[_name] = _exec); }
static PrecompiledExecutor registerExecutor(std::string const& _name, PrecompiledExecutor const& _exec) { return (get()->m_execs[_name] = _exec); }
/// Unregister an executor. Shouldn't generally be necessary.
static void unregisterExecutor(std::string const& _name) { get()->m_execs.erase(_name); }

/// Register a pricer. In general just use ETH_REGISTER_PRECOMPILED_PRICER.
static PrecompiledPricer registerPricer(std::string const& _name, PrecompiledPricer const& _exec) { return (get()->m_pricers[_name] = _exec); }
// Check if pricer registered
static bool isPricerRegistered(std::string const& _name) { return get()->m_pricers.find(_name) != get()->m_pricers.end(); }
/// Unregister an executor. Shouldn't generally be necessary.
static void unregisterPrecompiled(std::string const& _name) { get()->m_execs.erase(_name); }
static void unregisterPricer(std::string const& _name) { get()->m_pricers.erase(_name); }

private:
static PrecompiledRegistrar* get() { if (!s_this) s_this = new PrecompiledRegistrar; return s_this; }

std::unordered_map<std::string, PrecompiledExecutor> m_execs;
std::unordered_map<std::string, PrecompiledPricer> m_pricers;
static PrecompiledRegistrar* s_this;
};

// TODO: unregister on unload with a static object.
#define ETH_REGISTER_PRECOMPILED(Name) static std::pair<bool, bytes> __eth_registerPrecompiledFunction ## Name(bytesConstRef _in); static PrecompiledExecutor __eth_registerPrecompiledFactory ## Name = ::dev::eth::PrecompiledRegistrar::registerPrecompiled(#Name, &__eth_registerPrecompiledFunction ## Name); static std::pair<bool, bytes> __eth_registerPrecompiledFunction ## Name

#define ETH_REGISTER_PRECOMPILED(Name) static std::pair<bool, bytes> __eth_registerPrecompiledFunction ## Name(bytesConstRef _in); static PrecompiledExecutor __eth_registerPrecompiledFactory ## Name = ::dev::eth::PrecompiledRegistrar::registerExecutor(#Name, &__eth_registerPrecompiledFunction ## Name); static std::pair<bool, bytes> __eth_registerPrecompiledFunction ## Name
#define ETH_REGISTER_PRECOMPILED_PRICER(Name) static bigint __eth_registerPricerFunction ## Name(bytesConstRef _in); static PrecompiledPricer __eth_registerPricerFactory ## Name = ::dev::eth::PrecompiledRegistrar::registerPricer(#Name, &__eth_registerPricerFunction ## Name); static bigint __eth_registerPricerFunction ## Name
}
}
4 changes: 3 additions & 1 deletion libethereum/Account.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,15 @@ AccountMap dev::eth::jsonToAccountMap(std::string const& _json, u256 const& _def
{
js::mObject p = o["precompiled"].get_obj();
auto n = p["name"].get_str();
if (!p.count("linear"))
if (!p.count("linear") && !PrecompiledRegistrar::isPricerRegistered(n))
{
cwarn << "No gas cost given for precompiled contract " << n;
throw;
}
try
{
// TODO handle non-linear

auto l = p["linear"].get_obj();
u256 startingBlock = 0;
if (p.count("startingBlock"))
Expand Down

0 comments on commit 3892679

Please sign in to comment.