@ -303,9 +303,14 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
assert correct_response == response
end
end
test " automatically verify contract via Eth Bytecode Interface " , %{ conn : conn } do
describe " /smart-contracts/{address_hash} <> eth_bytecode_db " do
test " automatically verify contract " , %{ conn : conn } do
{ :ok , pid } = Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand . start_link ( [ ] )
old_chain_id = Application . get_env ( :block_scout_web , :chain_id )
Application . put_env ( :block_scout_web , :chain_id , 5 )
bypass = Bypass . open ( )
eth_bytecode_response = File . read! ( " ./test/support/fixture/smart_contract/eth_bytecode_db_search_response.json " )
@ -333,7 +338,77 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
|> socket ( " no_id " , %{ } )
|> subscribe_and_join ( topic )
Bypass . expect_once ( bypass , " POST " , " /api/v2/bytecodes/sources:search " , fn conn ->
Bypass . expect_once ( bypass , " POST " , " /api/v2/bytecodes/sources_search_all " , fn conn ->
Conn . resp ( conn , 200 , eth_bytecode_response )
end )
request = get ( conn , " /api/v2/smart-contracts/ #{ Address . checksum ( address . hash ) } " )
assert_receive % Phoenix.Socket.Message {
payload : %{ } ,
event : " smart_contract_was_verified " ,
topic : ^ topic
} ,
:timer . seconds ( 1 )
response = json_response ( request , 200 )
assert response ==
%{
" is_self_destructed " = > false ,
" deployed_bytecode " = > to_string ( address . contract_code ) ,
" creation_bytecode " = >
" 0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582061b7676067d537e410bb704932a9984739a959416170ea17bda192ac1218d2790029 "
}
request = get ( conn , " /api/v2/smart-contracts/ #{ Address . checksum ( address . hash ) } " )
assert response = json_response ( request , 200 )
assert %{ " is_verified " = > true } = response
assert %{ " is_verified_via_eth_bytecode_db " = > true } = response
assert %{ " is_partially_verified " = > true } = response
assert %{ " is_fully_verified " = > false } = response
Application . put_env ( :block_scout_web , :chain_id , old_chain_id )
Application . put_env ( :explorer , Explorer.SmartContract.RustVerifierInterfaceBehaviour , old_env )
Bypass . down ( bypass )
GenServer . stop ( pid )
end
test " automatically verify contract using search-all (ethBytecodeDbSources) endpoint " , %{ conn : conn } do
{ :ok , pid } = Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand . start_link ( [ ] )
old_chain_id = Application . get_env ( :block_scout_web , :chain_id )
Application . put_env ( :block_scout_web , :chain_id , 5 )
bypass = Bypass . open ( )
eth_bytecode_response =
File . read! ( " ./test/support/fixture/smart_contract/eth_bytecode_db_search_all_local_sources_response.json " )
old_env = Application . get_env ( :explorer , Explorer.SmartContract.RustVerifierInterfaceBehaviour )
Application . put_env ( :explorer , Explorer.SmartContract.RustVerifierInterfaceBehaviour ,
service_url : " http://localhost: #{ bypass . port } " ,
enabled : true
)
address = insert ( :contract_address )
insert ( :transaction ,
created_contract_address_hash : address . hash ,
input :
" 0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582061b7676067d537e410bb704932a9984739a959416170ea17bda192ac1218d2790029 "
)
|> with_block ( )
topic = " addresses: #{ address . hash } "
{ :ok , _reply , _socket } =
BlockScoutWeb.UserSocketV2
|> socket ( " no_id " , %{ } )
|> subscribe_and_join ( topic )
Bypass . expect_once ( bypass , " POST " , " /api/v2/bytecodes/sources_search_all " , fn conn ->
Conn . resp ( conn , 200 , eth_bytecode_response )
end )
@ -363,13 +438,236 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
assert %{ " is_partially_verified " = > true } = response
assert %{ " is_fully_verified " = > false } = response
smart_contract = Jason . decode! ( eth_bytecode_response ) [ " ethBytecodeDbSources " ] |> List . first ( )
assert response [ " compiler_settings " ] == Jason . decode! ( smart_contract [ " compilerSettings " ] )
assert response [ " name " ] == smart_contract [ " contractName " ]
assert response [ " compiler_version " ] == smart_contract [ " compilerVersion " ]
assert response [ " file_path " ] == smart_contract [ " fileName " ]
assert response [ " constructor_args " ] == smart_contract [ " constructorArguments " ]
assert response [ " abi " ] == Jason . decode! ( smart_contract [ " abi " ] )
assert response [ " decoded_constructor_args " ] == [
[
" 0xc35dadb65012ec5796536bd9864ed8773abc74c4 " ,
%{
" internalType " = > " address " ,
" name " = > " _factory " ,
" type " = > " address "
}
] ,
[
" 0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6 " ,
%{
" internalType " = > " address " ,
" name " = > " _WETH " ,
" type " = > " address "
}
]
]
assert response [ " source_code " ] == smart_contract [ " sourceFiles " ] [ smart_contract [ " fileName " ] ]
assert response [ " external_libraries " ] == [
%{
" address_hash " = > " 0x00000000D41867734BBee4C6863D9255b2b06aC1 " ,
" name " = > " __CACHE_BREAKER__ "
}
]
additional_sources =
for file_name <- Map . keys ( smart_contract [ " sourceFiles " ] ) , smart_contract [ " fileName " ] != file_name do
%{
" source_code " = > smart_contract [ " sourceFiles " ] [ file_name ] ,
" file_path " = > file_name
}
end
assert response [ " additional_sources " ] |> Enum . sort_by ( fn x -> x [ " file_path " ] end ) ==
additional_sources |> Enum . sort_by ( fn x -> x [ " file_path " ] end )
Application . put_env ( :block_scout_web , :chain_id , old_chain_id )
Application . put_env ( :explorer , Explorer.SmartContract.RustVerifierInterfaceBehaviour , old_env )
Bypass . down ( bypass )
GenServer . stop ( pid )
end
test " check fetch interval for LookUpSmartContractSourcesOnDemand " , %{ conn : conn } do
test " automatically verify contract using search-all (sourcifySources) endpoint " , %{ conn : conn } do
{ :ok , pid } = Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand . start_link ( [ ] )
old_chain_id = Application . get_env ( :block_scout_web , :chain_id )
Application . put_env ( :block_scout_web , :chain_id , 5 )
bypass = Bypass . open ( )
eth_bytecode_response =
File . read! ( " ./test/support/fixture/smart_contract/eth_bytecode_db_search_all_sourcify_sources_response.json " )
old_env = Application . get_env ( :explorer , Explorer.SmartContract.RustVerifierInterfaceBehaviour )
Application . put_env ( :explorer , Explorer.SmartContract.RustVerifierInterfaceBehaviour ,
service_url : " http://localhost: #{ bypass . port } " ,
enabled : true
)
address = insert ( :contract_address )
insert ( :transaction ,
created_contract_address_hash : address . hash ,
input :
" 0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582061b7676067d537e410bb704932a9984739a959416170ea17bda192ac1218d2790029 "
)
|> with_block ( )
topic = " addresses: #{ address . hash } "
{ :ok , _reply , _socket } =
BlockScoutWeb.UserSocketV2
|> socket ( " no_id " , %{ } )
|> subscribe_and_join ( topic )
Bypass . expect_once ( bypass , " POST " , " /api/v2/bytecodes/sources_search_all " , fn conn ->
Conn . resp ( conn , 200 , eth_bytecode_response )
end )
request = get ( conn , " /api/v2/smart-contracts/ #{ Address . checksum ( address . hash ) } " )
assert_receive % Phoenix.Socket.Message {
payload : %{ } ,
event : " smart_contract_was_verified " ,
topic : ^ topic
} ,
:timer . seconds ( 1 )
response = json_response ( request , 200 )
assert response ==
%{
" is_self_destructed " = > false ,
" deployed_bytecode " = > to_string ( address . contract_code ) ,
" creation_bytecode " = >
" 0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582061b7676067d537e410bb704932a9984739a959416170ea17bda192ac1218d2790029 "
}
request = get ( conn , " /api/v2/smart-contracts/ #{ Address . checksum ( address . hash ) } " )
assert response = json_response ( request , 200 )
assert %{ " is_verified " = > true } = response
assert %{ " is_verified_via_eth_bytecode_db " = > true } = response
assert %{ " is_verified_via_sourcify " = > true } = response
assert %{ " is_partially_verified " = > true } = response
assert %{ " is_fully_verified " = > false } = response
assert response [ " file_path " ] == " Test.sol "
Application . put_env ( :block_scout_web , :chain_id , old_chain_id )
Application . put_env ( :explorer , Explorer.SmartContract.RustVerifierInterfaceBehaviour , old_env )
Bypass . down ( bypass )
GenServer . stop ( pid )
end
test " automatically verify contract using search-all (sourcifySources with libraries) endpoint " , %{ conn : conn } do
{ :ok , pid } = Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand . start_link ( [ ] )
old_chain_id = Application . get_env ( :block_scout_web , :chain_id )
Application . put_env ( :block_scout_web , :chain_id , 5 )
bypass = Bypass . open ( )
eth_bytecode_response =
File . read! (
" ./test/support/fixture/smart_contract/eth_bytecode_db_search_all_sourcify_sources_with_libs_response.json "
)
old_env = Application . get_env ( :explorer , Explorer.SmartContract.RustVerifierInterfaceBehaviour )
Application . put_env ( :explorer , Explorer.SmartContract.RustVerifierInterfaceBehaviour ,
service_url : " http://localhost: #{ bypass . port } " ,
enabled : true
)
address = insert ( :contract_address )
insert ( :transaction ,
created_contract_address_hash : address . hash ,
input :
" 0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582061b7676067d537e410bb704932a9984739a959416170ea17bda192ac1218d2790029 "
)
|> with_block ( )
topic = " addresses: #{ address . hash } "
{ :ok , _reply , _socket } =
BlockScoutWeb.UserSocketV2
|> socket ( " no_id " , %{ } )
|> subscribe_and_join ( topic )
Bypass . expect_once ( bypass , " POST " , " /api/v2/bytecodes/sources_search_all " , fn conn ->
Conn . resp ( conn , 200 , eth_bytecode_response )
end )
request = get ( conn , " /api/v2/smart-contracts/ #{ Address . checksum ( address . hash ) } " )
assert_receive % Phoenix.Socket.Message {
payload : %{ } ,
event : " smart_contract_was_verified " ,
topic : ^ topic
} ,
:timer . seconds ( 1 )
response = json_response ( request , 200 )
assert response ==
%{
" is_self_destructed " = > false ,
" deployed_bytecode " = > to_string ( address . contract_code ) ,
" creation_bytecode " = >
" 0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582061b7676067d537e410bb704932a9984739a959416170ea17bda192ac1218d2790029 "
}
request = get ( conn , " /api/v2/smart-contracts/ #{ Address . checksum ( address . hash ) } " )
assert response = json_response ( request , 200 )
smart_contract = Jason . decode! ( eth_bytecode_response ) [ " sourcifySources " ] |> List . first ( )
assert %{ " is_verified " = > true } = response
assert %{ " is_verified_via_eth_bytecode_db " = > true } = response
assert %{ " is_verified_via_sourcify " = > true } = response
assert %{ " is_partially_verified " = > true } = response
assert %{ " is_fully_verified " = > false } = response
assert response [ " file_path " ] == " src/zkbob/ZkBobPool.sol "
assert response [ " external_libraries " ] == [
%{
" address_hash " = > " 0x22DE6B06544Ee5Cd907813a04bcdEd149A2f49D2 " ,
" name " = > " lib/base58-solidity/contracts/Base58.sol:Base58 "
} ,
%{
" address_hash " = > " 0x019d3788F00a7087234f3844CB1ceCe1F9982B7A " ,
" name " = > " src/libraries/ZkAddress.sol:ZkAddress "
}
]
additional_sources =
for file_name <- Map . keys ( smart_contract [ " sourceFiles " ] ) , smart_contract [ " fileName " ] != file_name do
%{
" source_code " = > smart_contract [ " sourceFiles " ] [ file_name ] ,
" file_path " = > file_name
}
end
assert response [ " additional_sources " ] |> Enum . sort_by ( fn x -> x [ " file_path " ] end ) ==
additional_sources |> Enum . sort_by ( fn x -> x [ " file_path " ] end )
Application . put_env ( :block_scout_web , :chain_id , old_chain_id )
Application . put_env ( :explorer , Explorer.SmartContract.RustVerifierInterfaceBehaviour , old_env )
Bypass . down ( bypass )
GenServer . stop ( pid )
end
test " check fetch interval for LookUpSmartContractSourcesOnDemand and use sources:search endpoint since chain_id is unset " ,
%{ conn : conn } do
{ :ok , pid } = Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand . start_link ( [ ] )
old_chain_id = Application . get_env ( :block_scout_web , :chain_id )
Application . put_env ( :block_scout_web , :chain_id , nil )
bypass = Bypass . open ( )
address = insert ( :contract_address )
@ -392,7 +690,7 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
Application . put_env ( :explorer , Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand , fetch_interval : 0 )
Bypass . expect_once ( bypass , " POST " , " /api/v2/bytecodes/sources: search " , fn conn ->
Bypass . expect_once ( bypass , " POST " , " /api/v2/bytecodes/sources_ search " , fn conn ->
Conn . resp ( conn , 200 , " { \" sources \" : []} " )
end )
@ -400,7 +698,7 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
:timer . sleep ( 10 )
Bypass . expect_once ( bypass , " POST " , " /api/v2/bytecodes/sources: search " , fn conn ->
Bypass . expect_once ( bypass , " POST " , " /api/v2/bytecodes/sources_ search " , fn conn ->
Conn . resp ( conn , 200 , " { \" sources \" : []} " )
end )
@ -408,7 +706,7 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
:timer . sleep ( 10 )
Bypass . expect_once ( bypass , " POST " , " /api/v2/bytecodes/sources: search " , fn conn ->
Bypass . expect_once ( bypass , " POST " , " /api/v2/bytecodes/sources_ search " , fn conn ->
Conn . resp ( conn , 200 , " { \" sources \" : []} " )
end )
@ -420,6 +718,7 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
_request = get ( conn , " /api/v2/smart-contracts/ #{ Address . checksum ( address . hash ) } " )
Application . put_env ( :block_scout_web , :chain_id , old_chain_id )
Application . put_env ( :explorer , Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand , old_interval_env )
Application . put_env ( :explorer , Explorer.SmartContract.RustVerifierInterfaceBehaviour , old_env )
Bypass . down ( bypass )