Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New deployment management #1893

Merged
merged 12 commits into from
May 15, 2024
17 changes: 17 additions & 0 deletions libethcore/Common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,26 @@ std::string formatBalance( bigint const& _b ) {
}

bytes isAddressWhitelistedCallData( Address const& _deployer ) {
// Generating calldata for isAddressWhitelisted contract call:
// 13f44d1 - selector of isAddressWhitelisted function
// 000000000000000000000000 - 12-byte offset for sender address
// _deployer - 20-byte sender address

return fromHex( "13f44d10000000000000000000000000" + _deployer.hex() );
}

bytes isDeploymentAllowedCallData( Address const& _origin, Address const& _deployer ) {
// Generating calldata for isDeploymentAllowed contract call:
// d0f557f4 - selector of isDeploymentAllowed function
// 000000000000000000000000 - 12-byte offset for origin address
// _origin - 20-byte origin address
// 000000000000000000000000 - 12-byte offset for sender address
// _deployer - 20-byte sender address

return fromHex( "d0f557f4000000000000000000000000" + _origin.hex() +
"000000000000000000000000" + _deployer.hex() );
}

bytes getMultitransactionCallData() {
return fromHex( "0xbad0396e" );
}
Expand Down
5 changes: 4 additions & 1 deletion libethcore/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,12 @@ extern const bytes c_blockhashContractCode;
/// Address of the special contract for deployment control
extern const Address c_configControllerContractAddress;

/// Formatting call data for deployment control contract
/// Generating call data for deployment control contract
bytes isAddressWhitelistedCallData( Address const& _deployer );

/// Generating calldata for deployment control contract, considering tx origin
bytes isDeploymentAllowedCallData( Address const& _origin, Address const& _deployer );

/// Formatting call data for multitransaction contract
bytes getMultitransactionCallData();

Expand Down
12 changes: 10 additions & 2 deletions libethereum/Executive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <libdevcore/microprofile.h>
#include <libethashseal/Ethash.h>
#include <libethcore/CommonJS.h>
#include <libethereum/SchainPatch.h>
#include <libevm/LegacyVM.h>
#include <libevm/VMFactory.h>

Expand Down Expand Up @@ -468,11 +469,18 @@ bool Executive::go( OnOpFunc const& _onOp ) {
// Create VM instance. Force Interpreter if tracing requested.
auto vm = VMFactory::create();
if ( m_isCreation ) {
bytes in = isAddressWhitelistedCallData( m_ext->caller );
// Checking whether deployment is allowed via ConfigController contract
bytes calldata;
if ( FlexibleDeploymentPatch::isEnabledWhen(
m_envInfo.committedBlockTimestamp() ) ) {
calldata = isDeploymentAllowedCallData( m_ext->origin, m_ext->caller );
} else {
calldata = isAddressWhitelistedCallData( m_ext->caller );
}
unique_ptr< CallParameters > deploymentCallParams(
new CallParameters( SystemAddress, c_configControllerContractAddress,
c_configControllerContractAddress, 0, 0, m_gas,
bytesConstRef( in.data(), in.size() ), {} ) );
bytesConstRef( calldata.data(), calldata.size() ), {} ) );
auto deploymentCallResult = m_ext->call( *deploymentCallParams );
auto deploymentCallOutput = dev::toHex( deploymentCallResult.output );
if ( !deploymentCallOutput.empty() && u256( deploymentCallOutput ) == 0 ) {
Expand Down
4 changes: 4 additions & 0 deletions libethereum/SchainPatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ SchainPatchEnum getEnumForPatchName( const std::string& _patchName ) {
return SchainPatchEnum::SkipInvalidTransactionsPatch;
else if ( _patchName == "EIP1559TransactionsPatch" )
return SchainPatchEnum::EIP1559TransactionsPatch;
else if ( _patchName == "FlexibleDeploymentPatch" )
return SchainPatchEnum::FlexibleDeploymentPatch;
else
throw std::out_of_range( _patchName );
}
Expand Down Expand Up @@ -60,6 +62,8 @@ std::string getPatchNameForEnum( SchainPatchEnum _enumValue ) {
return "SelfdestructStorageLimitPatch";
case SchainPatchEnum::EIP1559TransactionsPatch:
return "EIP1559TransactionsPatch";
case SchainPatchEnum::FlexibleDeploymentPatch:
return "FlexibleDeploymentPatch";
default:
throw std::out_of_range(
"UnknownPatch #" + std::to_string( static_cast< size_t >( _enumValue ) ) );
Expand Down
6 changes: 6 additions & 0 deletions libethereum/SchainPatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,10 @@ DEFINE_SIMPLE_PATCH( SelfdestructStorageLimitPatch );
*/
DEFINE_SIMPLE_PATCH( EIP1559TransactionsPatch );

/*
* Purpose: passing both transaction origin and sender to the ConfigController contract
* Version introduced: 3.19.0
*/
DEFINE_SIMPLE_PATCH( FlexibleDeploymentPatch );

#endif // SCHAINPATCH_H
1 change: 1 addition & 0 deletions libethereum/SchainPatchEnum.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ enum class SchainPatchEnum {
SkipInvalidTransactionsPatch,
SelfdestructStorageLimitPatch,
EIP1559TransactionsPatch,
FlexibleDeploymentPatch,
PatchesCount
};

Expand Down
115 changes: 115 additions & 0 deletions test/unittests/libweb3jsonrpc/jsonrpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3358,6 +3358,121 @@ BOOST_AUTO_TEST_CASE( deploy_controller_generation2 ) {
BOOST_REQUIRE( code.asString().substr( 2 ) == compiled.substr( 58 ) );
}

BOOST_AUTO_TEST_CASE( deployment_control_v2 ) {

// Inserting ConfigController mockup into config and enabling flexibleDeploymentPatch.
// ConfigController mockup contract:

// pragma solidity ^0.8.9;
// contract ConfigController {
// bool public freeContractDeployment = false;
// function isAddressWhitelisted(address addr) external view returns (bool) {
// return false;
// }
// function isDeploymentAllowed(address origin, address sender)
// external view returns (bool) {
// return freeContractDeployment;
// }
// function setFreeContractDeployment() external {
// freeContractDeployment = true;
// }
// }

string configControllerV2 =
"0x608060405234801561001057600080fd5b506004361061004c576000"
"3560e01c806313f44d1014610051578063a2306c4f14610081578063d0"
"f557f41461009f578063f7e2a91b146100cf575b600080fd5b61006b60"
"048036038101906100669190610189565b6100d9565b60405161007891"
"906101d1565b60405180910390f35b6100896100e0565b604051610096"
"91906101d1565b60405180910390f35b6100b960048036038101906100"
"b491906101ec565b6100f1565b6040516100c691906101d1565b604051"
"80910390f35b6100d761010a565b005b6000919050565b600080549061"
"01000a900460ff1681565b60008060009054906101000a900460ff1690"
"5092915050565b60016000806101000a81548160ff0219169083151502"
"17905550565b600080fd5b600073ffffffffffffffffffffffffffffff"
"ffffffffff82169050919050565b60006101568261012b565b90509190"
"50565b6101668161014b565b811461017157600080fd5b50565b600081"
"3590506101838161015d565b92915050565b6000602082840312156101"
"9f5761019e610126565b5b60006101ad84828501610174565b91505092"
"915050565b60008115159050919050565b6101cb816101b6565b825250"
"50565b60006020820190506101e660008301846101c2565b9291505056"
"5b6000806040838503121561020357610202610126565b5b6000610211"
"85828601610174565b925050602061022285828601610174565b915050"
"925092905056fea2646970667358221220b5f971b16f7bbba22272b220"
"7e02f10abf1682c17fe636c7bf6406c5cae5716064736f6c63430008090033";

std::string _config = c_genesisGeneration2ConfigString;
Json::Value ret;
Json::Reader().parse( _config, ret );
ret["accounts"]["0xD2002000000000000000000000000000000000d2"]["code"] = configControllerV2;
ret["skaleConfig"]["sChain"]["flexibleDeploymentPatchTimestamp"] = 1;
Json::FastWriter fastWriter;
std::string config = fastWriter.write( ret );

JsonRpcFixture fixture(config, false, false, true );
Address senderAddress = fixture.coinbase.address();
fixture.client->setAuthor( senderAddress );

// contract test {
// function f(uint a) returns(uint d) { return a * 7; }
// }

string compiled =
"6080604052341561000f57600080fd5b60b98061001d6000396000f300"
"608060405260043610603f576000357c01000000000000000000000000"
"00000000000000000000000000000000900463ffffffff168063b3de64"
"8b146044575b600080fd5b3415604e57600080fd5b606a600480360381"
"019080803590602001909291905050506080565b604051808281526020"
"0191505060405180910390f35b60006007820290509190505600a16562"
"7a7a72305820f294e834212334e2978c6dd090355312a3f0f9476b8eb9"
"8fb480406fc2728a960029";


// Trying to deploy contract without permission
Json::Value deployContractWithoutRoleTx;
deployContractWithoutRoleTx["from"] = senderAddress.hex();
deployContractWithoutRoleTx["code"] = compiled;
deployContractWithoutRoleTx["gas"] = "1000000";
deployContractWithoutRoleTx["gasPrice"] = fixture.rpcClient->eth_gasPrice();

string txHash = fixture.rpcClient->eth_sendTransaction( deployContractWithoutRoleTx );
dev::eth::mineTransaction( *( fixture.client ), 1 );

Json::Value receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash );
BOOST_REQUIRE_EQUAL( receipt["status"], string( "0x0" ) );

Json::Value code =
fixture.rpcClient->eth_getCode( receipt["contractAddress"].asString(), "latest" );
BOOST_REQUIRE( code.asString() == "0x" );

// Allow to deploy by calling setFreeContractDeployment()
Json::Value grantDeployerRoleTx;
grantDeployerRoleTx["data"] = "0xf7e2a91b";
grantDeployerRoleTx["from"] = senderAddress.hex();
grantDeployerRoleTx["to"] = "0xD2002000000000000000000000000000000000D2";
grantDeployerRoleTx["gasPrice"] = fixture.rpcClient->eth_gasPrice();
grantDeployerRoleTx["gas"] = toJS( "1000000" );
txHash = fixture.rpcClient->eth_sendTransaction( grantDeployerRoleTx );
BOOST_REQUIRE( !txHash.empty() );
dev::eth::mineTransaction( *( fixture.client ), 1 );

// Deploying with permission
Json::Value deployContractTx;
deployContractTx["from"] = senderAddress.hex();
deployContractTx["code"] = compiled;
deployContractTx["gas"] = "1000000";
deployContractTx["gasPrice"] = fixture.rpcClient->eth_gasPrice();

txHash = fixture.rpcClient->eth_sendTransaction( deployContractTx );
dev::eth::mineTransaction( *( fixture.client ), 1 );

receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash );
BOOST_REQUIRE_EQUAL( receipt["status"], string( "0x1" ) );
BOOST_REQUIRE( !receipt["contractAddress"].isNull() );
code = fixture.rpcClient->eth_getCode( receipt["contractAddress"].asString(), "latest" );
BOOST_REQUIRE( code.asString().substr( 2 ) == compiled.substr( 58 ) );
}

BOOST_AUTO_TEST_CASE( filestorage_generation2 ) {
JsonRpcFixture fixture(c_genesisGeneration2ConfigString, false, false, true);

Expand Down
Loading