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

Commit cea171f

Browse files
committed
EIP198: Custom cost function for modexp contract
1 parent 18773f8 commit cea171f

File tree

5 files changed

+73
-31
lines changed

5 files changed

+73
-31
lines changed

libethcore/ChainOperationParams.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ PrecompiledContract::PrecompiledContract(
3232
PrecompiledExecutor const& _exec,
3333
u256 const& _startingBlock
3434
):
35-
PrecompiledContract([=](unsigned size) -> bigint
35+
PrecompiledContract([=](bytesConstRef _in) -> bigint
3636
{
37-
bigint s = size;
37+
bigint s = _in.size();
3838
bigint b = _base;
3939
bigint w = _word;
4040
return b + (s + 31) / 32 * w;

libethcore/ChainOperationParams.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class PrecompiledContract
3737
public:
3838
PrecompiledContract() = default;
3939
PrecompiledContract(
40-
std::function<bigint(size_t)> const& _cost,
40+
PrecompiledPricer const& _cost,
4141
PrecompiledExecutor const& _exec,
4242
u256 const& _startingBlock = 0
4343
):
@@ -52,13 +52,13 @@ class PrecompiledContract
5252
u256 const& _startingBlock = 0
5353
);
5454

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

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

6060
private:
61-
std::function<bigint(size_t)> m_cost;
61+
PrecompiledPricer m_cost;
6262
PrecompiledExecutor m_execute;
6363
u256 m_startingBlock = 0;
6464
};

libethcore/Precompiled.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ PrecompiledExecutor const& PrecompiledRegistrar::executor(std::string const& _na
3838
return get()->m_execs[_name];
3939
}
4040

41+
PrecompiledPricer const& PrecompiledRegistrar::pricer(std::string const& _name)
42+
{
43+
if (!get()->m_pricers.count(_name))
44+
BOOST_THROW_EXCEPTION(PricerNotFound());
45+
return get()->m_pricers[_name];
46+
}
47+
4148
namespace
4249
{
4350

@@ -122,4 +129,15 @@ ETH_REGISTER_PRECOMPILED(modexp)(bytesConstRef _in)
122129
return {true, ret};
123130
}
124131

132+
ETH_REGISTER_PRECOMPILED_PRICER(modexp)(bytesConstRef _in)
133+
{
134+
u256 const baseLength(parseBigEndianRightPadded<u256>(_in, 0, 32));
135+
u256 const expLength(parseBigEndianRightPadded<u256>(_in, 32, 32));
136+
u256 const modLength(parseBigEndianRightPadded<u256>(_in, 64, 32));
137+
138+
bigint const maxLength = max(modLength, baseLength);
139+
140+
return maxLength * maxLength * max<bigint>(expLength, 1) / 20;
141+
}
142+
125143
}

libethcore/Precompiled.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,29 +32,40 @@ namespace eth
3232
{
3333

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

3637
DEV_SIMPLE_EXCEPTION(ExecutorNotFound);
38+
DEV_SIMPLE_EXCEPTION(PricerNotFound);
3739

3840
class PrecompiledRegistrar
3941
{
4042
public:
4143
/// Get the executor object for @a _name function or @throw ExecutorNotFound if not found.
4244
static PrecompiledExecutor const& executor(std::string const& _name);
4345

46+
/// Get the price calculator object for @a _name function or @throw PricerNotFound if not found.
47+
static PrecompiledPricer const& pricer(std::string const& _name);
48+
4449
/// Register an executor. In general just use ETH_REGISTER_PRECOMPILED.
45-
static PrecompiledExecutor registerPrecompiled(std::string const& _name, PrecompiledExecutor const& _exec) { return (get()->m_execs[_name] = _exec); }
50+
static PrecompiledExecutor registerExecutor(std::string const& _name, PrecompiledExecutor const& _exec) { return (get()->m_execs[_name] = _exec); }
51+
/// Unregister an executor. Shouldn't generally be necessary.
52+
static void unregisterExecutor(std::string const& _name) { get()->m_execs.erase(_name); }
53+
54+
/// Register a pricer. In general just use ETH_REGISTER_PRECOMPILED_PRICER.
55+
static PrecompiledPricer registerPricer(std::string const& _name, PrecompiledPricer const& _exec) { return (get()->m_pricers[_name] = _exec); }
4656
/// Unregister an executor. Shouldn't generally be necessary.
47-
static void unregisterPrecompiled(std::string const& _name) { get()->m_execs.erase(_name); }
57+
static void unregisterPricer(std::string const& _name) { get()->m_pricers.erase(_name); }
4858

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

5262
std::unordered_map<std::string, PrecompiledExecutor> m_execs;
63+
std::unordered_map<std::string, PrecompiledPricer> m_pricers;
5364
static PrecompiledRegistrar* s_this;
5465
};
5566

5667
// TODO: unregister on unload with a static object.
57-
#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
58-
68+
#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
69+
#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
5970
}
6071
}

libethereum/Account.cpp

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ void Account::setNewCode(bytes&& _code)
3737

3838
namespace js = json_spirit;
3939

40+
namespace
41+
{
42+
4043
uint64_t toUnsigned(js::mValue const& _v)
4144
{
4245
switch (_v.type())
@@ -47,6 +50,37 @@ uint64_t toUnsigned(js::mValue const& _v)
4750
}
4851
}
4952

53+
PrecompiledContract createPrecompiledContract(js::mObject& _precompiled)
54+
{
55+
auto n = _precompiled["name"].get_str();
56+
try
57+
{
58+
u256 startingBlock = 0;
59+
if (_precompiled.count("startingBlock"))
60+
startingBlock = u256(_precompiled["startingBlock"].get_str());
61+
62+
if (!_precompiled.count("linear"))
63+
return PrecompiledContract(PrecompiledRegistrar::pricer(n), PrecompiledRegistrar::executor(n), startingBlock);
64+
65+
auto l = _precompiled["linear"].get_obj();
66+
unsigned base = toUnsigned(l["base"]);
67+
unsigned word = toUnsigned(l["word"]);
68+
return PrecompiledContract(base, word, PrecompiledRegistrar::executor(n), startingBlock);
69+
}
70+
catch (PricerNotFound const&)
71+
{
72+
cwarn << "Couldn't create a precompiled contract account. Missing a pricer called:" << n;
73+
throw;
74+
}
75+
catch (ExecutorNotFound const&)
76+
{
77+
// Oh dear - missing a plugin?
78+
cwarn << "Couldn't create a precompiled contract account. Missing an executor called:" << n;
79+
throw;
80+
}
81+
}
82+
83+
}
5084
AccountMap dev::eth::jsonToAccountMap(std::string const& _json, u256 const& _defaultNonce, AccountMaskMap* o_mask, PrecompiledContractMap* o_precompiled)
5185
{
5286
auto u256Safe = [](std::string const& s) -> u256 {
@@ -115,28 +149,7 @@ AccountMap dev::eth::jsonToAccountMap(std::string const& _json, u256 const& _def
115149
if (o_precompiled && o.count("precompiled"))
116150
{
117151
js::mObject p = o["precompiled"].get_obj();
118-
auto n = p["name"].get_str();
119-
if (!p.count("linear"))
120-
{
121-
cwarn << "No gas cost given for precompiled contract " << n;
122-
throw;
123-
}
124-
try
125-
{
126-
auto l = p["linear"].get_obj();
127-
u256 startingBlock = 0;
128-
if (p.count("startingBlock"))
129-
startingBlock = u256(p["startingBlock"].get_str());
130-
unsigned base = toUnsigned(l["base"]);
131-
unsigned word = toUnsigned(l["word"]);
132-
o_precompiled->insert(make_pair(a, PrecompiledContract(base, word, PrecompiledRegistrar::executor(n), startingBlock)));
133-
}
134-
catch (ExecutorNotFound)
135-
{
136-
// Oh dear - missing a plugin?
137-
cwarn << "Couldn't create a precompiled contract account. Missing an executor called:" << n;
138-
throw;
139-
}
152+
o_precompiled->insert(make_pair(a, createPrecompiledContract(p)));
140153
}
141154
}
142155

0 commit comments

Comments
 (0)