Skip to content

Commit

Permalink
Merge pull request #1893 from skalenetwork/enhancement/new-deploy-man…
Browse files Browse the repository at this point in the history
…agement

New deployment management
  • Loading branch information
DmytroNazarenko authored May 15, 2024
2 parents 006c55a + aa957df commit e1f053a
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 3 deletions.
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

0 comments on commit e1f053a

Please sign in to comment.