diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 1c9772b55..cb889a51a 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -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" ); } diff --git a/libethcore/Common.h b/libethcore/Common.h index 980aa7a30..b48b5ffd4 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -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(); diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 70a945efc..242245ba7 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -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 ) { diff --git a/libethereum/SchainPatch.cpp b/libethereum/SchainPatch.cpp index bcbe90274..065b74210 100644 --- a/libethereum/SchainPatch.cpp +++ b/libethereum/SchainPatch.cpp @@ -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 ); } @@ -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 ) ) ); diff --git a/libethereum/SchainPatch.h b/libethereum/SchainPatch.h index bb630691c..c31628975 100644 --- a/libethereum/SchainPatch.h +++ b/libethereum/SchainPatch.h @@ -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 diff --git a/libethereum/SchainPatchEnum.h b/libethereum/SchainPatchEnum.h index 10fa231c9..313432999 100644 --- a/libethereum/SchainPatchEnum.h +++ b/libethereum/SchainPatchEnum.h @@ -17,6 +17,7 @@ enum class SchainPatchEnum { SkipInvalidTransactionsPatch, SelfdestructStorageLimitPatch, EIP1559TransactionsPatch, + FlexibleDeploymentPatch, PatchesCount }; diff --git a/test/unittests/libweb3jsonrpc/jsonrpc.cpp b/test/unittests/libweb3jsonrpc/jsonrpc.cpp index d7a33fd49..570017327 100644 --- a/test/unittests/libweb3jsonrpc/jsonrpc.cpp +++ b/test/unittests/libweb3jsonrpc/jsonrpc.cpp @@ -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);