Browse Source

PoC-7 crypto-contracts.

cl-refactor
Gav Wood 10 years ago
parent
commit
81c16c7290
  1. 16
      libdevcrypto/SHA3.cpp
  2. 6
      libdevcrypto/SHA3.h
  3. 5
      libethereum/Executive.cpp
  4. 18
      libethereum/ExtVM.h
  5. 65
      libethereum/State.cpp
  6. 12
      libethereum/State.h
  7. 9
      libevm/ExtVMFace.h
  8. 6
      test/vm.cpp

16
libdevcrypto/SHA3.cpp

@ -58,6 +58,22 @@ void sha3(bytesConstRef _input, bytesRef _output)
ctx.Final(_output.data()); ctx.Final(_output.data());
} }
void ripemd160(bytesConstRef _input, bytesRef _output)
{
CryptoPP::RIPEMD160 ctx;
ctx.Update((byte*)_input.data(), _input.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
void sha256(bytesConstRef _input, bytesRef _output)
{
CryptoPP::SHA256 ctx;
ctx.Update((byte*)_input.data(), _input.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
bytes sha3Bytes(bytesConstRef _input) bytes sha3Bytes(bytesConstRef _input)
{ {
bytes ret(32); bytes ret(32);

6
libdevcrypto/SHA3.h

@ -60,7 +60,13 @@ inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input))
extern h256 EmptySHA3; extern h256 EmptySHA3;
// Other crypto convenience routines
bytes aesDecrypt(bytesConstRef _cipher, std::string const& _password, unsigned _rounds = 2000, bytesConstRef _salt = bytesConstRef()); bytes aesDecrypt(bytesConstRef _cipher, std::string const& _password, unsigned _rounds = 2000, bytesConstRef _salt = bytesConstRef());
void sha256(bytesConstRef _input, bytesRef _output);
void ripemd160(bytesConstRef _input, bytesRef _output);
} }
} }

5
libethereum/Executive.cpp

@ -218,15 +218,12 @@ u256 Executive::gas() const
return m_vm ? m_vm->gas() : m_endGas; return m_vm ? m_vm->gas() : m_endGas;
} }
void Executive::finalize(OnOpFunc const& _onOp) void Executive::finalize(OnOpFunc const&)
{ {
if (m_t.isCreation() && m_newAddress && m_out.size()) if (m_t.isCreation() && m_newAddress && m_out.size())
// non-reverted creation - put code in place. // non-reverted creation - put code in place.
m_s.m_cache[m_newAddress].setCode(m_out); m_s.m_cache[m_newAddress].setCode(m_out);
if (m_ext)
m_endGas += m_ext->doPosts(_onOp);
// cnote << "Refunding" << formatBalance(m_endGas * m_ext->gasPrice) << "to origin (=" << m_endGas << "*" << formatBalance(m_ext->gasPrice) << ")"; // cnote << "Refunding" << formatBalance(m_endGas * m_ext->gasPrice) << "to origin (=" << m_endGas << "*" << formatBalance(m_ext->gasPrice) << ")";
m_s.addBalance(m_sender, m_endGas * m_t.gasPrice); m_s.addBalance(m_sender, m_endGas * m_t.gasPrice);

18
libethereum/ExtVM.h

@ -61,7 +61,7 @@ public:
m_s.noteSending(myAddress); m_s.noteSending(myAddress);
if (m_ms) if (m_ms)
m_ms->internal.resize(m_ms->internal.size() + 1); m_ms->internal.resize(m_ms->internal.size() + 1);
auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &suicides, &posts, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, level + 1); auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, level + 1);
if (m_ms && !m_ms->internal.back().from) if (m_ms && !m_ms->internal.back().from)
m_ms->internal.pop_back(); m_ms->internal.pop_back();
return ret; return ret;
@ -72,7 +72,7 @@ public:
{ {
if (m_ms) if (m_ms)
m_ms->internal.resize(m_ms->internal.size() + 1); m_ms->internal.resize(m_ms->internal.size() + 1);
auto ret = m_s.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &suicides, &posts, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, level + 1); auto ret = m_s.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, level + 1);
if (m_ms && !m_ms->internal.back().from) if (m_ms && !m_ms->internal.back().from)
m_ms->internal.pop_back(); m_ms->internal.pop_back();
return ret; return ret;
@ -98,20 +98,6 @@ public:
/// @TODO check call site for the parent manifest being discarded. /// @TODO check call site for the parent manifest being discarded.
void revert() { if (m_ms) *m_ms = Manifest(); m_s.m_cache = m_origCache; } void revert() { if (m_ms) *m_ms = Manifest(); m_s.m_cache = m_origCache; }
/// Execute any posts we have left.
u256 doPosts(OnOpFunc const& _onOp = OnOpFunc())
{
u256 ret;
while (posts.size())
{
Post& p = posts.front();
call(p.to, p.value, &p.data, &p.gas, bytesRef(), _onOp, p.from);
ret += p.gas;
posts.pop_front();
}
return ret;
}
State& state() const { return m_s; } State& state() const { return m_s; }
/// @note not a part of the main API; just for use by tracing/debug stuff. /// @note not a part of the main API; just for use by tracing/debug stuff.

65
libethereum/State.cpp

@ -41,6 +41,50 @@ using namespace dev::eth;
static const u256 c_blockReward = 1500 * finney; static const u256 c_blockReward = 1500 * finney;
void ecrecoverCode(bytesConstRef _in, bytesRef _out)
{
struct inType
{
h256 hash;
h256 v;
h256 r;
h256 s;
} in;
h256 ret;
memcpy(&in, _in.data(), min(_in.size(), sizeof(in)));
byte pubkey[65];
int pubkeylen = 65;
secp256k1_start();
if (secp256k1_ecdsa_recover_compact(in.hash.data(), 32, in.r.data(), pubkey, &pubkeylen, 0, (int)(u256)in.v - 27))
ret = dev::eth::sha3(bytesConstRef(&(pubkey[1]), 64));
memcpy(_out.data(), &ret, min(_out.size(), sizeof(ret)));
}
void sha256Code(bytesConstRef _in, bytesRef _out)
{
h256 ret;
sha256(_in, bytesRef(ret.data(), 32));
memcpy(_out.data(), &ret, min(_out.size(), sizeof(ret)));
}
void ripemd160Code(bytesConstRef _in, bytesRef _out)
{
h256 ret;
ripemd160(_in, bytesRef(ret.data(), 32));
memcpy(_out.data(), &ret, min(_out.size(), sizeof(ret)));
}
const std::map<unsigned, PrecompiledAddress> State::c_precompiled =
{
{ 1, { 500, ecrecoverCode }},
{ 2, { 100, sha256Code }},
{ 3, { 100, ripemd160Code }}
};
OverlayDB State::openDB(std::string _path, bool _killExisting) OverlayDB State::openDB(std::string _path, bool _killExisting)
{ {
if (_path.empty()) if (_path.empty())
@ -1061,7 +1105,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
return e.gasUsed(); return e.gasUsed();
} }
bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress, std::set<Address>* o_suicides, PostList* o_posts, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress, std::set<Address>* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
{ {
if (!_originAddress) if (!_originAddress)
_originAddress = _senderAddress; _originAddress = _senderAddress;
@ -1077,7 +1121,16 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
o_ms->input = _data.toBytes(); o_ms->input = _data.toBytes();
} }
if (addressHasCode(_codeAddress)) auto it = !(_codeAddress & ~h160(0xffffffff)) ? c_precompiled.find((unsigned)(u160)_codeAddress) : c_precompiled.end();
if (it != c_precompiled.end())
{
if (*_gas >= it->second.gas)
{
*_gas -= it->second.gas;
it->second.exec(_data, _out);
}
}
else if (addressHasCode(_codeAddress))
{ {
VM vm(*_gas); VM vm(*_gas);
ExtVM evm(*this, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &code(_codeAddress), o_ms, _level); ExtVM evm(*this, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &code(_codeAddress), o_ms, _level);
@ -1090,9 +1143,6 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
if (o_suicides) if (o_suicides)
for (auto i: evm.suicides) for (auto i: evm.suicides)
o_suicides->insert(i); o_suicides->insert(i);
if (o_posts)
for (auto i: evm.posts)
o_posts->push_back(i);
if (o_ms) if (o_ms)
o_ms->output = out.toBytes(); o_ms->output = out.toBytes();
} }
@ -1125,7 +1175,7 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
return true; return true;
} }
h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, std::set<Address>* o_suicides, PostList* o_posts, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, std::set<Address>* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
{ {
if (!_origin) if (!_origin)
_origin = _sender; _origin = _sender;
@ -1157,9 +1207,6 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas,
if (o_suicides) if (o_suicides)
for (auto i: evm.suicides) for (auto i: evm.suicides)
o_suicides->insert(i); o_suicides->insert(i);
if (o_posts)
for (auto i: evm.posts)
o_posts->push_back(i);
} }
catch (OutOfGas const& /*_e*/) catch (OutOfGas const& /*_e*/)
{ {

12
libethereum/State.h

@ -69,6 +69,12 @@ struct TransactionReceipt
Manifest changes; Manifest changes;
}; };
struct PrecompiledAddress
{
unsigned gas;
std::function<void(bytesConstRef, bytesRef)> exec;
};
/** /**
* @brief Model of the current state of the ledger. * @brief Model of the current state of the ledger.
* Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block). * Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block).
@ -277,12 +283,12 @@ private:
// We assume all instrinsic fees are paid up before this point. // We assume all instrinsic fees are paid up before this point.
/// Execute a contract-creation transaction. /// Execute a contract-creation transaction.
h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = Address(), std::set<Address>* o_suicides = nullptr, PostList* o_posts = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0); h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = Address(), std::set<Address>* o_suicides = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0);
/// Execute a call. /// Execute a call.
/// @a _gas points to the amount of gas to use for the call, and will lower it accordingly. /// @a _gas points to the amount of gas to use for the call, and will lower it accordingly.
/// @returns false if the call ran out of gas before completion. true otherwise. /// @returns false if the call ran out of gas before completion. true otherwise.
bool call(Address _myAddress, Address _codeAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256* _gas, bytesRef _out, Address _originAddress = Address(), std::set<Address>* o_suicides = nullptr, PostList* o_posts = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0); bool call(Address _myAddress, Address _codeAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256* _gas, bytesRef _out, Address _originAddress = Address(), std::set<Address>* o_suicides = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0);
/// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock). /// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock).
void resetCurrent(); void resetCurrent();
@ -321,6 +327,8 @@ private:
static std::string c_defaultPath; static std::string c_defaultPath;
static const std::map<unsigned, PrecompiledAddress> c_precompiled;
friend std::ostream& operator<<(std::ostream& _out, State const& _s); friend std::ostream& operator<<(std::ostream& _out, State const& _s);
}; };

9
libevm/ExtVMFace.h

@ -42,8 +42,6 @@ struct Post
u256 gas; u256 gas;
}; };
using PostList = std::list<Post>;
using OnOpFunc = std::function<void(uint64_t /*steps*/, Instruction /*instr*/, bigint /*newMemSize*/, bigint /*gasCost*/, void/*VM*/*, void/*ExtVM*/ const*)>; using OnOpFunc = std::function<void(uint64_t /*steps*/, Instruction /*instr*/, bigint /*newMemSize*/, bigint /*gasCost*/, void/*VM*/*, void/*ExtVM*/ const*)>;
/** /**
@ -88,15 +86,9 @@ public:
/// Make a new message call. /// Make a new message call.
bool call(Address, u256, bytesConstRef, u256*, bytesRef, OnOpFunc const&, Address, Address) { return false; } bool call(Address, u256, bytesConstRef, u256*, bytesRef, OnOpFunc const&, Address, Address) { return false; }
/// Post a new message call.
void post(Address _to, u256 _value, bytesConstRef _data, u256 _gas) { posts.push_back(Post({myAddress, _to, _value, _data.toBytes(), _gas})); }
/// Revert any changes made (by any of the other calls). /// Revert any changes made (by any of the other calls).
void revert() {} void revert() {}
/// Execute any posts that may exist, including those that are incurred as a result of earlier posts.
void doPosts() {}
Address myAddress; ///< Address associated with executing code (a contract, or contract-to-be). Address myAddress; ///< Address associated with executing code (a contract, or contract-to-be).
Address caller; ///< Address which sent the message (either equal to origin or a contract). Address caller; ///< Address which sent the message (either equal to origin or a contract).
Address origin; ///< Original transactor. Address origin; ///< Original transactor.
@ -107,7 +99,6 @@ public:
BlockInfo previousBlock; ///< The previous block's information. BlockInfo previousBlock; ///< The previous block's information.
BlockInfo currentBlock; ///< The current block's information. BlockInfo currentBlock; ///< The current block's information.
std::set<Address> suicides; ///< Any accounts that have suicided. std::set<Address> suicides; ///< Any accounts that have suicided.
std::list<Post> posts; ///< Any posts that have been made.
}; };
} }

6
test/vm.cpp

@ -45,7 +45,7 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun
m_s.noteSending(myAddress); m_s.noteSending(myAddress);
m_ms.internal.resize(m_ms.internal.size() + 1); m_ms.internal.resize(m_ms.internal.size() + 1);
auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &suicides, &posts, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1); auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1);
if (!m_ms.internal.back().from) if (!m_ms.internal.back().from)
m_ms.internal.pop_back(); m_ms.internal.pop_back();
@ -83,7 +83,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
{ {
m_s.noteSending(myAddress); m_s.noteSending(myAddress);
m_ms.internal.resize(m_ms.internal.size() + 1); m_ms.internal.resize(m_ms.internal.size() + 1);
auto na = m_s.create(myAddress, 0, gasPrice, _gas, init, origin, &suicides, &posts, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1); auto na = m_s.create(myAddress, 0, gasPrice, _gas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1);
if (!m_ms.internal.back().from) if (!m_ms.internal.back().from)
m_ms.internal.pop_back(); m_ms.internal.pop_back();
if (!m_s.addresses().count(_receiveAddress)) if (!m_s.addresses().count(_receiveAddress))
@ -96,7 +96,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
} }
m_ms.internal.resize(m_ms.internal.size() + 1); m_ms.internal.resize(m_ms.internal.size() + 1);
auto ret = m_s.call(_receiveAddress, Address() ? Address() : _receiveAddress, Address() ? Address() : myAddress, _value, gasPrice, _data, _gas, _out, origin, &suicides, &posts, &(m_ms.internal.back()), OnOpFunc(), 1); auto ret = m_s.call(_receiveAddress, Address() ? Address() : _receiveAddress, Address() ? Address() : myAddress, _value, gasPrice, _data, _gas, _out, origin, &suicides, &(m_ms.internal.back()), OnOpFunc(), 1);
if (!m_ms.internal.back().from) if (!m_ms.internal.back().from)
m_ms.internal.pop_back(); m_ms.internal.pop_back();
if (!ret) if (!ret)

Loading…
Cancel
Save