Skip to content

Commit

Permalink
Prepare EVM Support Changes (#2037)
Browse files Browse the repository at this point in the history
* Port all CPP changes from feature/evm to master

* Add file to check for args

* lint: add local deps

* test: add evm category

* Fix typo

* Add more CPP changes

---------

Co-authored-by: Niven <[email protected]>
  • Loading branch information
Bushstar and sieniven authored Jun 9, 2023
1 parent 262202e commit 34c7757
Show file tree
Hide file tree
Showing 51 changed files with 673 additions and 228 deletions.
15 changes: 14 additions & 1 deletion src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ class CMainParams : public CChainParams {
consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated);
consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community);

// EVM chain id
consensus.evmChainId = 1130; // ETH main chain ID

/**
* The message start string is designed to be unlikely to occur in normal data.
* The characters are rarely used upper ASCII, not valid as UTF-8, and produce
Expand Down Expand Up @@ -499,6 +502,9 @@ class CTestNetParams : public CChainParams {
consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated);
consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community);

// EVM chain id
consensus.evmChainId = 1131; // test chain ID

pchMessageStartPostAMK[0] = pchMessageStart[0] = 0x0b;
pchMessageStartPostAMK[1] = pchMessageStart[1] = 0x11;
pchMessageStartPostAMK[2] = pchMessageStart[2] = 0x09;
Expand Down Expand Up @@ -627,7 +633,7 @@ class CDevNetParams : public CChainParams {
consensus.FortCanningEpilogueHeight = 1244000;
consensus.GrandCentralHeight = 1366000;
consensus.GrandCentralEpilogueHeight = 1438200;
consensus.NextNetworkUpgradeHeight = std::numeric_limits<int>::max();
consensus.NextNetworkUpgradeHeight = 1586750;

consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.pos.nTargetTimespan = 5 * 60; // 5 min == 10 blocks
Expand Down Expand Up @@ -711,6 +717,9 @@ class CDevNetParams : public CChainParams {
consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated);
consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community);

// EVM chain id
consensus.evmChainId = 1132; // dev chain ID

pchMessageStartPostAMK[0] = pchMessageStart[0] = 0x0c;
pchMessageStartPostAMK[1] = pchMessageStart[1] = 0x10;
pchMessageStartPostAMK[2] = pchMessageStart[2] = 0x10;
Expand Down Expand Up @@ -773,6 +782,7 @@ class CDevNetParams : public CChainParams {
vSeeds.clear();
// nodes with support for servicebits filtering should be at the top
vSeeds.emplace_back("35.187.53.161");
vSeeds.emplace_back("34.89.47.54");
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_devnet, pnSeed6_devnet + ARRAYLEN(pnSeed6_devnet));

fDefaultConsistencyChecks = false;
Expand Down Expand Up @@ -926,6 +936,9 @@ class CRegTestParams : public CChainParams {
consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated);
consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community);

// EVM chain id
consensus.evmChainId = 1133; // regtest chain ID

pchMessageStartPostAMK[0] = pchMessageStart[0] = 0xfa;
pchMessageStartPostAMK[1] = pchMessageStart[1] = 0xbf;
pchMessageStartPostAMK[2] = pchMessageStart[2] = 0xb5;
Expand Down
3 changes: 2 additions & 1 deletion src/chainparamsseeds.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ static SeedSpec6 pnSeed6_test[] = {
};

static SeedSpec6 pnSeed6_devnet[] = {
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x12,0xc5,0xa1,0x0e}, 20555}
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x23,0xbb,0x35,0xa1}, 20555},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x22,0x59,0x00,0x67}, 20555}
};
#endif // DEFI_CHAINPARAMSSEEDS_H
2 changes: 1 addition & 1 deletion src/compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <limits.h>
#include <limits>
#include <netdb.h>
#include <unistd.h>
#endif
Expand Down
2 changes: 2 additions & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ struct Params {

std::map<CommunityAccountType, CAmount> nonUtxoBlockSubsidies;
std::map<CommunityAccountType, uint32_t> newNonUTXOSubsidies;

uint64_t evmChainId;
};
} // namespace Consensus

Expand Down
21 changes: 20 additions & 1 deletion src/consensus/tx_check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
}

// Check for duplicate inputs - note that this check is slow so we skip it in CheckBlock
if (fCheckDuplicateInputs) {
if (!IsEVMTx(tx) && fCheckDuplicateInputs) {
std::set<COutPoint> vInOutPoints;
for (const auto& txin : tx.vin)
{
Expand All @@ -55,6 +55,11 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
if (tx.vin[0].scriptSig.size() < 2 || (tx.vin[0].scriptSig.size() > 100))
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-length");
}
else if (IsEVMTx(tx))
{
if (tx.vin[0].scriptSig.size() != 1 || tx.vin[1].scriptSig.size() != 1)
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-evm-length");
}
else
{
for (const auto& txin : tx.vin)
Expand Down Expand Up @@ -132,3 +137,17 @@ bool IsTokenSplitTx(CTransaction const & tx, std::vector<unsigned char> & metada
}
return result;
}

bool IsEVMTx(const CTransaction &tx) {
std::vector<uint8_t> metadata;
auto hasAdditionalOpcodes{false};
return (tx.vin.size() == 2 &&
tx.vin[0].prevout.IsNull() &&
tx.vin[1].prevout.IsNull() &&
tx.vout.size() == 1 &&
tx.vout[0].scriptPubKey.size() > 0 &&
tx.vout[0].scriptPubKey[0] == OP_RETURN &&
tx.vout[0].nValue == 0 &&
ParseScriptByMarker(tx.vout[0].scriptPubKey, DfTxMarker, metadata, hasAdditionalOpcodes) &&
metadata[0] == '9');
}
1 change: 1 addition & 0 deletions src/consensus/tx_check.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ bool ParseScriptByMarker(CScript const & script,
bool IsAnchorRewardTx(CTransaction const & tx, std::vector<unsigned char> & metadata, bool fortCanning = false);
bool IsAnchorRewardTxPlus(CTransaction const & tx, std::vector<unsigned char> & metadata, bool fortCanning = false);
bool IsTokenSplitTx(CTransaction const & tx, std::vector<unsigned char> & metadata, bool fortCanningCrunch = true);
bool IsEVMTx(const CTransaction &tx);

#endif // DEFI_CONSENSUS_TX_CHECK_H
6 changes: 5 additions & 1 deletion src/consensus/tx_verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
{
int64_t nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR;

if (tx.IsCoinBase())
if (tx.IsCoinBase() || IsEVMTx(tx))
return nSigOps;

if (flags & SCRIPT_VERIFY_P2SH) {
Expand All @@ -163,6 +163,10 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i

bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, CCustomCSView& mnview, int nSpendHeight, CAmount& txfee, const CChainParams& chainparams)
{
if (IsEVMTx(tx)) {
return true;
}

// are the actual inputs available?
if (!inputs.HaveInputs(tx)) {
return state.Invalid(ValidationInvalidReason::TX_MISSING_INPUTS, false, REJECT_INVALID, "bad-txns-inputs-missingorspent",
Expand Down
5 changes: 3 additions & 2 deletions src/defid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ static void WaitForShutdown()
//
static bool AppInit(int argc, char* argv[])
{
preinit();
InitInterfaces interfaces;
interfaces.chain = interfaces::MakeChain();

Expand Down Expand Up @@ -163,6 +164,7 @@ static bool AppInit(int argc, char* argv[])
// If locking the data directory failed, exit immediately
return false;
}
init_evm_runtime();
fRet = AppInitMain(interfaces);
}
catch (const std::exception& e) {
Expand All @@ -178,8 +180,7 @@ static bool AppInit(int argc, char* argv[])
WaitForShutdown();
}
Shutdown(interfaces);

stop_runtime();
stop_evm_runtime();

return fRet;
}
Expand Down
1 change: 1 addition & 0 deletions src/fs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#endif
#include <codecvt>
#include <windows.h>
#include <limits>
#endif

namespace fsbridge {
Expand Down
61 changes: 52 additions & 9 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,8 +638,10 @@ void SetupServerArgs()
gArgs.AddArg("-dftxworkers=<n>", strprintf("No. of parallel workers associated with the DfTx related work pool. Stock splits, parallel processing of the chain where appropriate, etc use this worker pool (default: %d)", DEFAULT_DFTX_WORKERS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-maxaddrratepersecond=<n>", strprintf("Sets MAX_ADDR_RATE_PER_SECOND limit for ADDR messages(default: %f)", MAX_ADDR_RATE_PER_SECOND), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
gArgs.AddArg("-maxaddrprocessingtokenbucket=<n>", strprintf("Sets MAX_ADDR_PROCESSING_TOKEN_BUCKET limit for ADDR messages(default: %d)", MAX_ADDR_PROCESSING_TOKEN_BUCKET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
gArgs.AddArg("-grpcbind=<addr>[:port]", "Bind to given address to listen for JSON-gRPC connections. Do not expose the gRPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -grpcport. This option can be specified multiple times (default: 127.0.0.1 i.e., localhost)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
gArgs.AddArg("-grpcport=<port>", strprintf("Start GRPC connections on <port> and <port + 1> (default: %u, testnet: %u, devnet: %u, regtest: %u)", defaultBaseParams->GRPCPort(), testnetBaseParams->GRPCPort(), devnetBaseParams->GRPCPort(), regtestBaseParams->GRPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
gArgs.AddArg("-ethrpcport=<port>", strprintf("Listen for ETH-JASON-RPC connections on <port>> (default: %u, testnet: %u, devnet: %u, regtest: %u)", defaultBaseParams->ETHRPCPort(), testnetBaseParams->ETHRPCPort(), devnetBaseParams->ETHRPCPort(), regtestBaseParams->ETHRPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
gArgs.AddArg("-ethrpcbind=<addr>[:port]", "Bind to given address to listen for ETH-JSON-RPC connections. Do not expose the ETH-RPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -ethrpcport. This option can be specified multiple times (default: 127.0.0.1 i.e., localhost)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
gArgs.AddArg("-ethrpcport=<port>", strprintf("Listen for ETH-JSON-RPC connections on <port>> (default: %u, testnet: %u, devnet: %u, regtest: %u)", defaultBaseParams->ETHRPCPort(), testnetBaseParams->ETHRPCPort(), devnetBaseParams->ETHRPCPort(), regtestBaseParams->ETHRPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);

#if HAVE_DECL_DAEMON
gArgs.AddArg("-daemon", "Run in the background as a daemon and accept commands", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
Expand Down Expand Up @@ -1255,7 +1257,6 @@ bool AppInitParameterInteraction()
}

maxAddrRatePerSecond = gArgs.GetDoubleArg("-maxaddrratepersecond", Params().NetworkIDString() == CBaseChainParams::REGTEST ? MAX_ADDR_RATE_PER_SECOND_REGTEST : MAX_ADDR_RATE_PER_SECOND);

if (maxAddrRatePerSecond <= static_cast<double>(0)) {
return InitError("maxaddrratepersecond cannot be configured with a negative value.");
}
Expand Down Expand Up @@ -1554,10 +1555,53 @@ bool AppInitMain(InitInterfaces& interfaces)

// ********************************************************* Step 4b: application initialization

init_runtime();
int grpc_port = gArgs.GetArg("-grpcport", BaseParams().GRPCPort());
/* Start the ETH RPC and gRPC servers. Current API only allows for one ETH
* RPC/gRPC server to bind to one address. By default, we will only take
* the first address, if multiple addresses are specified.
*/
int eth_rpc_port = gArgs.GetArg("-ethrpcport", BaseParams().ETHRPCPort());
start_servers("127.0.0.1:" + std::to_string(eth_rpc_port), "127.0.0.1:" + std::to_string(grpc_port));
int grpc_port = gArgs.GetArg("-grpcport", BaseParams().GRPCPort());
std::vector<std::pair<std::string, uint16_t> > eth_endpoints;
std::vector<std::pair<std::string, uint16_t> > g_endpoints;

// Determine which addresses to bind to ETH RPC server
if (!(gArgs.IsArgSet("-rpcallowip") && gArgs.IsArgSet("-ethrpcbind"))) { // Default to loopback if not allowing external IPs
eth_endpoints.push_back(std::make_pair("127.0.0.1", eth_rpc_port));
if (gArgs.IsArgSet("-rpcallowip")) {
LogPrintf("WARNING: option -rpcallowip was specified without -ethrpcbind; this doesn't usually make sense\n");
}
if (gArgs.IsArgSet("-ethrpcbind")) {
LogPrintf("WARNING: option -ethrpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
}
} else if (gArgs.IsArgSet("-ethrpcbind")) { // Specific bind address
for (const std::string& strETHRPCBind : gArgs.GetArgs("-ethrpcbind")) {
int port = eth_rpc_port;
std::string host;
SplitHostPort(strETHRPCBind, port, host);
eth_endpoints.push_back(std::make_pair(host, port));
}
}

// Determine which addresses to bind to gRPC server
if (!(gArgs.IsArgSet("-rpcallowip") && gArgs.IsArgSet("-grpcbind"))) { // Default to loopback if not allowing external IPs
g_endpoints.push_back(std::make_pair("127.0.0.1", grpc_port));
if (gArgs.IsArgSet("-rpcallowip")) {
LogPrintf("WARNING: option -rpcallowip was specified without -grpcbind; this doesn't usually make sense\n");
}
if (gArgs.IsArgSet("-grpcbind")) {
LogPrintf("WARNING: option -grpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
}
} else if (gArgs.IsArgSet("-grpcbind")) { // Specific bind address
for (const std::string& strGRPCBind : gArgs.GetArgs("-grpcbind")) {
int port = grpc_port;
std::string host;
SplitHostPort(strGRPCBind, port, host);
g_endpoints.push_back(std::make_pair(host, port));
}
}

// Default to using the first address passed to bind to ETH RPC server and gRPC server
start_servers(eth_endpoints[0].first + ":" + std::to_string(eth_endpoints[0].second), g_endpoints[0].first + "." + std::to_string(g_endpoints[0].second));

// ********************************************************* Step 5: verify wallet database integrity
for (const auto& client : interfaces.chain_clients) {
Expand Down Expand Up @@ -2218,9 +2262,8 @@ bool AppInitMain(InitInterfaces& interfaces)

// Import privkey
const auto key = DecodeSecret("L5DhrVPhA2FbJ1ezpN3JijHVnnH1sVcbdcAcp3nE373ooGH6LEz6");
const auto pubkey = key.GetPubKey();
const auto dest = WitnessV0KeyHash(PKHash{pubkey});
const auto keyID = pubkey.GetID();
const auto keyID = key.GetPubKey().GetID();
const auto dest = WitnessV0KeyHash(PKHash{keyID});
const auto time{std::time(nullptr)};

auto pwallet = GetWallets()[0];
Expand Down Expand Up @@ -2289,7 +2332,7 @@ bool AppInitMain(InitInterfaces& interfaces)

bool found = false;
for (auto wallet : wallets) {
if (::IsMine(*wallet, destination)) {
if (::IsMine(*wallet, destination) & ISMINE_SPENDABLE) {
found = true;
break;
}
Expand Down
2 changes: 1 addition & 1 deletion src/key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ bool CKey::Load(const CPrivKey &privkey, const CPubKey &vchPubKey, bool fSkipChe

return VerifyPubKey(vchPubKey);
}
#include <logging.h>

bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc, const bool ethAddress) const {
assert(IsValid());
assert(IsCompressed());
Expand Down
17 changes: 16 additions & 1 deletion src/key_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,22 @@ class DestinationEncoder

std::string operator()(const WitnessV16EthHash& id) const
{
return ETH_ADDR_PREFIX + HexStr(id);
// Raw addr = ETH_ADDR_PREFIX + HexStr(id);
// Produce ETH checksum address: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md
const auto address = HexStr(id);
std::vector<unsigned char> input(address.begin(), address.end());
std::vector<unsigned char> output;
sha3(input, output);
const auto hashedAddress = HexStr(output);
std::string result;
for (size_t i{}; i < address.size(); ++i) {
if (std::isdigit(address[i]) || hashedAddress[i] < '8') {
result += address[i];
} else {
result += std::toupper(address[i]);
}
}
return ETH_ADDR_PREFIX + result;
}

std::string operator()(const CNoDestination& no) const { return {}; }
Expand Down
2 changes: 1 addition & 1 deletion src/masternodes/balances.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ struct CUtxosToAccountMessage {
}
};

enum VMDomain : uint8_t {
enum class VMDomain : uint8_t {
NONE = 0x00,
// UTXO Reserved
UTXO = 0x01,
Expand Down
Loading

0 comments on commit 34c7757

Please sign in to comment.