Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 51 additions & 1 deletion src/contract/contracthost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,29 @@ static inline bool isCall(const evmc_message& msg) {
return msg.kind == EVMC_CALL || msg.kind == EVMC_DELEGATECALL;
}

static Address ecrecover(const Hash& hash, uint8_t v, const Hash& r, const Hash& s) {
if (v == 27) {
v = 0;
} else if (v == 28) {
v = 1;
} else {
return Address{};
}

Signature sig;
auto it = std::copy(r.begin(), r.end(), sig.begin());
it = std::copy(s.begin(), s.end(), it);
*it = v;

auto pubkey = Secp256k1::recover(sig, hash);

if (!pubkey) {
return Address{};
}

return Secp256k1::toAddress(pubkey);
}

void ContractHost::transfer(const Address& from, const Address& to, const uint256_t& value) {
// the from account **Must exist** on the unordered_map.
// unordered_map references to values are valid **until** you insert a new element
Expand Down Expand Up @@ -243,6 +266,11 @@ evmc::Result ContractHost::processBDKPrecompile(const evmc_message& msg) {
* function getRandom() external view returns (uint256);
* }
*/

if (msg.recipient == ECRECOVER_PRECOMPILE) {
return this->processEcRecoverPrecompile(msg);
}

try {
this->leftoverGas_ = msg.gas;
this->deduceGas(1000); // CPP contract call is 1000 gas
Expand All @@ -261,6 +289,21 @@ evmc::Result ContractHost::processBDKPrecompile(const evmc_message& msg) {
return evmc::Result(EVMC_PRECOMPILE_FAILURE, this->leftoverGas_, 0, nullptr, 0);
}

evmc::Result ContractHost::processEcRecoverPrecompile(const evmc_message& msg) {
try {
this->deduceGas(3000); // The cost for a ecrecover call: https://www.evm.codes/precompiled
const auto [hash, v, r, s] = ABI::Decoder::decodeData<Hash, uint8_t, Hash, Hash>(bytes::View(msg.input_data, msg.input_size));
const Address result = ecrecover(hash, v, r, s);
const Bytes resultEncoded = ABI::Encoder::encodeData(result);
return evmc::Result{EVMC_SUCCESS, this->leftoverGas_, 0, resultEncoded.data(), resultEncoded.size()};
} catch (const std::exception& e) {
this->evmcThrows_.emplace_back(e.what());
this->evmcThrow_ = true;
}

return evmc::Result(EVMC_PRECOMPILE_FAILURE, this->leftoverGas_, 0, nullptr, 0);
}

void ContractHost::execute(const evmc_message& msg, const ContractType& type) {
const Address from(msg.sender);
const Address to(msg.recipient);
Expand Down Expand Up @@ -619,7 +662,14 @@ ContractType ContractHost::decodeContractCallType(const evmc_message& msg) const
return ContractType::CREATE2;
}
default:
if (msg.recipient == BDK_PRECOMPILE) return ContractType::PRECOMPILED;
if (msg.recipient == BDK_PRECOMPILE) {
return ContractType::PRECOMPILED;
}

if (msg.recipient == ECRECOVER_PRECOMPILE) {
return ContractType::PRECOMPILED;
}

Address recipient(msg.recipient);
// we need to take a reference to the account, not a reference to the pointer
const auto& recipientAccount = *accounts_[recipient];
Expand Down
8 changes: 8 additions & 0 deletions src/contract/contracthost.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ See the LICENSE.txt file in the project root for more information.
using namespace evmc::literals;
const auto ZERO_ADDRESS = 0x0000000000000000000000000000000000000000_address;
const auto BDK_PRECOMPILE = 0x1000000000000000000000000000100000000001_address;
const auto ECRECOVER_PRECOMPILE = 0x0000000000000000000000000000000000000001_address;

/// Abstraction for a contract host.
class ContractHost : public evmc::Host {
Expand Down Expand Up @@ -152,6 +153,13 @@ class ContractHost : public evmc::Host {
*/
evmc::Result processBDKPrecompile(const evmc_message& msg);

/**
* Process a call to EC RECOVER precompile.
* @param msg The call message to process.
* @return The result of the call.
*/
evmc::Result processEcRecoverPrecompile(const evmc_message& msg);

/**
* Process an EVM CREATE call.
* @param msg The call message to process.
Expand Down
1 change: 1 addition & 0 deletions src/utils/dynamicexception.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ See the LICENSE.txt file in the project root for more information.
#define DYNAMIC_EXCEPTION_H

#include <chrono> // ctime
#include <iomanip>
#include <sstream> // ostringstream

/// Abstraction of a custom exception class for dynamic message building and timestamping.
Expand Down