diff --git a/etherlink/CHANGES_NODE.md b/etherlink/CHANGES_NODE.md index bc6f240264eb9872564662ffc1dbb292ae20e260..1c67936b7115825f9f7dc473961b3c90cbebc9b1 100644 --- a/etherlink/CHANGES_NODE.md +++ b/etherlink/CHANGES_NODE.md @@ -13,6 +13,9 @@ the store (!18713). ### RPCs changes +- Revert outputting EIP-55 encoded addresses in the RPC responses. This is not + a standard behavior for nodes of EVM-compatible chains. (!18757) + ### Metrics changes ### Command-line interface changes diff --git a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml index 95442b79fd17035278f52541a191ad5d8d66a8e5..ef2ce3545ac0bd68976584b54730892722c5c8af 100644 --- a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml +++ b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml @@ -70,27 +70,7 @@ type address = Address of hex [@@ocaml.unboxed] let address_of_string s = Address (hex_of_string (String.lowercase_ascii s)) -let address_to_string (Address (Hex address)) = - (* Implementation compliant with EIP-55 - See https://eips.ethereum.org/EIPS/eip-55 *) - let hexchar_to_int c = - if '0' <= c && c <= '9' then Char.code c - Char.code '0' - else if 'A' <= c && c <= 'F' then Char.code c - Char.code 'A' + 10 - else if 'a' <= c && c <= 'f' then Char.code c - Char.code 'a' + 10 - else raise (Invalid_argument "address_to_string: not a valid address") - in - - let hash = Digestif.KECCAK_256.(to_hex @@ digest_string address) in - let address = Bytes.of_string address in - - Bytes.iteri - (fun i c -> - if 'a' <= c && c <= 'f' then - let hash_nibble = hexchar_to_int (String.get hash i) in - if hash_nibble >= 8 then Bytes.set address i (Char.uppercase_ascii c)) - address ; - - "0x" ^ Bytes.to_string address +let address_to_string (Address a) = hex_to_string a let address_encoding = Data_encoding.(conv address_to_string address_of_string string) @@ -564,7 +544,7 @@ type 'transaction_object block = { transactionRoot : hash; stateRoot : hash; receiptRoot : hash; - miner : address; + miner : hex; difficulty : quantity; totalDifficulty : quantity; extraData : hex; @@ -626,8 +606,8 @@ let block_from_rlp_v0 bytes = have that, potentially this could be the sequencer. *) let miner = decode_option - ~default:(Address (Hex "0000000000000000000000000000000000000000")) - decode_address + ~default:(Hex "0000000000000000000000000000000000000000") + decode_hex miner in let transactionRoot = @@ -726,8 +706,8 @@ let block_from_rlp_v1 bytes = have that, potentially this could be the sequencer. *) let miner = decode_option - ~default:(Address (Hex "0000000000000000000000000000000000000000")) - decode_address + ~default:(Hex "0000000000000000000000000000000000000000") + decode_hex miner in let transactionRoot = @@ -948,7 +928,7 @@ let block_encoding transaction_object_encoding = (req "transactionsRoot" hash_encoding) (req "stateRoot" hash_encoding) (req "receiptsRoot" hash_encoding) - (req "miner" address_encoding)) + (req "miner" hex_encoding)) (obj10 (req "difficulty" quantity_encoding) (req "totalDifficulty" quantity_encoding) @@ -1099,6 +1079,28 @@ module Address = struct let to_string = address_to_string let of_string = address_of_string + + let to_eip55_string (Address (Hex address)) = + (* Implementation compliant with EIP-55 + See https://eips.ethereum.org/EIPS/eip-55 *) + let hexchar_to_int c = + if '0' <= c && c <= '9' then Char.code c - Char.code '0' + else if 'A' <= c && c <= 'F' then Char.code c - Char.code 'A' + 10 + else if 'a' <= c && c <= 'f' then Char.code c - Char.code 'a' + 10 + else raise (Invalid_argument "address_to_string: not a valid address") + in + + let hash = Digestif.KECCAK_256.(to_hex @@ digest_string address) in + let address = Bytes.of_string address in + + Bytes.iteri + (fun i c -> + if 'a' <= c && c <= 'f' then + let hash_nibble = hexchar_to_int (String.get hash i) in + if hash_nibble >= 8 then Bytes.set address i (Char.uppercase_ascii c)) + address ; + + "0x" ^ Bytes.to_string address end module AddressMap = MapMake (Address) diff --git a/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli b/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli index 9f855b92a66ac6f94ec848e79f5cc46d56200f52..f89aea18e9adff44e9c6a3e0ff7f09873fdd3f5b 100644 --- a/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli +++ b/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli @@ -184,7 +184,7 @@ type 'transaction_object block = { transactionRoot : hash; stateRoot : hash; receiptRoot : hash; - miner : address; + miner : hex; difficulty : quantity; totalDifficulty : quantity; extraData : hex; @@ -302,6 +302,8 @@ module Address : sig val to_string : t -> string val of_string : string -> t + + val to_eip55_string : t -> string end (** [timestamp_to_bytes timestamp] transforms the timestamp to bytes diff --git a/etherlink/bin_node/lib_dev/evm_store.ml b/etherlink/bin_node/lib_dev/evm_store.ml index 0f01f797692b1c3cac14118ec237232ab23d1e69..1ff9f88d05f6ad884556135a2bb82374b9dabe42 100644 --- a/etherlink/bin_node/lib_dev/evm_store.ml +++ b/etherlink/bin_node/lib_dev/evm_store.ml @@ -125,7 +125,7 @@ module Legacy_encodings = struct (req "transactionsRoot" hash_encoding) (req "stateRoot" hash_encoding) (req "receiptsRoot" hash_encoding) - (req "miner" address_encoding)) + (req "miner" hex_encoding)) (obj10 (req "difficulty" quantity_encoding) (req "totalDifficulty" quantity_encoding) diff --git a/etherlink/bin_node/main.ml b/etherlink/bin_node/main.ml index 1372799cd91e0aa7a01529f8d72196fe20022a64..98e2cd12a543bc2a0822a86ef704a784b3b66c5d 100644 --- a/etherlink/bin_node/main.ml +++ b/etherlink/bin_node/main.ml @@ -1456,7 +1456,7 @@ let show_kms_key_info_command = fprintf fmt "@ Ethereum address: %s" - (Ethereum_types.Address.to_string addr))) + (Ethereum_types.Address.to_eip55_string addr))) eth_opt ; return_unit | None -> diff --git a/etherlink/tezt/tests/evm_rollup.ml b/etherlink/tezt/tests/evm_rollup.ml index aca0083086d4e31402d0ad7ea11589815262070c..e3b3d5daeaca2f25d100561242a3237eba93cabc 100644 --- a/etherlink/tezt/tests/evm_rollup.ml +++ b/etherlink/tezt/tests/evm_rollup.ml @@ -770,8 +770,9 @@ let deploy_with_base_checks {contract; expected_address} full_evm_setup = let endpoint = Evm_node.endpoint evm_node in let sender = Eth_account.bootstrap_accounts.(0) in let* contract_address, tx = deploy ~contract ~sender full_evm_setup in + let address = String.lowercase_ascii contract_address in Check.( - (contract_address = expected_address) + (address = expected_address) string ~error_msg:"Expected address to be %R but was %L.") ; let* code_in_kernel = @@ -1235,7 +1236,7 @@ let test_l2_deploy_simple_storage = deploy_with_base_checks { contract = simple_storage_resolved; - expected_address = "0xd77420F73B4612a7A99DBA8c2AFd30a1886b0344"; + expected_address = "0xd77420f73b4612a7a99dba8c2afd30a1886b0344"; } evm_setup @@ -1369,7 +1370,8 @@ let test_l2_deploy_erc20 = (* deploy the contract *) let* address, tx = deploy ~contract:erc20_resolved ~sender evm_setup in Check.( - (address = "0xd77420F73B4612a7A99DBA8c2AFd30a1886b0344") + (String.lowercase_ascii address + = "0xd77420f73b4612a7a99dba8c2afd30a1886b0344") string ~error_msg:"Expected address to be %R but was %L.") ; @@ -1488,7 +1490,7 @@ let test_deploy_contract_with_push0 = deploy_with_base_checks { contract = shanghai_storage_resolved; - expected_address = "0xd77420F73B4612a7A99DBA8c2AFd30a1886b0344"; + expected_address = "0xd77420f73b4612a7a99dba8c2afd30a1886b0344"; } evm_setup @@ -1537,7 +1539,7 @@ let test_log_index = ~gas_price:1_000_000_000 ~gas:27_638 ~value:Wei.zero - ~address:"0xd77420F73B4612a7A99DBA8c2AFd30a1886b0344" + ~address:"0xd77420f73b4612a7a99dba8c2afd30a1886b0344" ~signature:"emitBoth(uint256)" ~arguments:["100"] () @@ -1550,7 +1552,7 @@ let test_log_index = ~gas_price:1_000_000_000 ~gas:25_664 ~value:Wei.zero - ~address:"0xd77420F73B4612a7A99DBA8c2AFd30a1886b0344" + ~address:"0xd77420f73b4612a7a99dba8c2afd30a1886b0344" ~signature:"emitA(uint256)" ~arguments:["10"] () @@ -1915,7 +1917,7 @@ let test_rpc_txpool_content = ~gas_price:100_000 ~gas:23_300 ~value:(Wei.of_string "100") - ~address:"0x11D3C9168db9d12a3C591061D555870969b43dC9" + ~address:"0x11d3c9168db9d12a3c591061d555870969b43dc9" () in let* tx2 = @@ -1926,7 +1928,7 @@ let test_rpc_txpool_content = ~gas_price:100_000 ~gas:23_300 ~value:(Wei.of_string "100") - ~address:"0x11D3C9168db9d12a3C591061D555870969b43dC9" + ~address:"0x11d3c9168db9d12a3c591061d555870969b43dc9" () in let*@ tx_hash1 = Rpc.send_raw_transaction ~raw_tx:tx1 evm_node in @@ -1959,12 +1961,12 @@ let test_rpc_txpool_content = let transaction_addr_queued = List.nth txpool_queued 0 in Check.( (transaction_addr_pending.address - = "0x6ce4d79d4E77402e1ef3417Fdda433aA744C6e1c") + = "0x6ce4d79d4e77402e1ef3417fdda433aa744c6e1c") string) ~error_msg:"Expected caller of transaction_1 to be %R, got %L." ; Check.( (transaction_addr_queued.address - = "0x6ce4d79d4E77402e1ef3417Fdda433aA744C6e1c") + = "0x6ce4d79d4e77402e1ef3417fdda433aa744c6e1c") string) ~error_msg:"Expected caller of transaction_2 to be %R, got %L." ; let num_pending_transaction_addr_1 = @@ -1994,13 +1996,13 @@ let test_rpc_txpool_content = ~transaction_content:pending_transaction_addr_1_content ~blockHash:"null" ~blockNumber:"null" - ~from:"0x6ce4d79d4E77402e1ef3417Fdda433aA744C6e1c" + ~from:"0x6ce4d79d4e77402e1ef3417fdda433aa744c6e1c" ~gas:"0x5b04" ~gasPrice:"0x186a0" ~hash:"0xed148f664807dfcb3c7095de22a6c63e72ae4f9d503549c525f5014327b51693" ~input:"0x" ~nonce:"0x0" - ~to_:"0x11D3C9168db9d12a3C591061D555870969b43dC9" + ~to_:"0x11d3c9168db9d12a3c591061d555870969b43dc9" ~transactionIndex:"null" ~value:"0x64" (* TODO: https://gitlab.com/tezos/tezos/-/issues/7194 @@ -2016,13 +2018,13 @@ let test_rpc_txpool_content = ~transaction_content:queued_transaction_addr_1_content ~blockHash:"null" ~blockNumber:"null" - ~from:"0x6ce4d79d4E77402e1ef3417Fdda433aA744C6e1c" + ~from:"0x6ce4d79d4e77402e1ef3417fdda433aa744c6e1c" ~gas:"0x5b04" ~gasPrice:"0x186a0" ~hash:"0x38b2831803a0f9a82bcc68f79bf167311b0adfe9e3d111a7f9579cdfcbae0f0f" ~input:"0x" ~nonce:"0x1" - ~to_:"0x11D3C9168db9d12a3C591061D555870969b43dC9" + ~to_:"0x11d3c9168db9d12a3c591061d555870969b43dc9" ~transactionIndex:"null" ~value:"0x64" (* TODO: https://gitlab.com/tezos/tezos/-/issues/7194 @@ -2369,7 +2371,7 @@ let test_estimate_gas_additionnal_field = let eth_call = [ ( "from", - Ezjsonm.encode_string @@ "0x6ce4d79d4E77402e1ef3417Fdda433aA744C6e1c" + Ezjsonm.encode_string @@ "0x6ce4d79d4e77402e1ef3417fdda433aa744c6e1c" ); ("data", Ezjsonm.encode_string @@ "0x" ^ data); ("value", Ezjsonm.encode_string @@ "0x0"); @@ -2398,7 +2400,8 @@ let test_eth_call_storage_contract = in let* () = check_tx_succeeded ~endpoint ~tx in Check.( - (address = "0xd77420F73B4612a7A99DBA8c2AFd30a1886b0344") + (String.lowercase_ascii address + = "0xd77420f73b4612a7a99dba8c2afd30a1886b0344") string ~error_msg:"Expected address to be %R but was %L.") ; @@ -4370,8 +4373,9 @@ let test_rpc_getLogs = let* erc20_resolved = erc20 evm_version in (* deploy the contract *) let* address, _tx = deploy ~contract:erc20_resolved ~sender evm_setup in + let address = String.lowercase_ascii address in Check.( - (address = "0xd77420F73B4612a7A99DBA8c2AFd30a1886b0344") + (address = "0xd77420f73b4612a7a99dba8c2afd30a1886b0344") string ~error_msg:"Expected address to be %R but was %L.") ; (* minting / burning *) @@ -4615,7 +4619,7 @@ let test_l2_revert_returns_unused_gas = ~gas_price:65_536 ~gas:100_000 ~value:Wei.zero - ~address:"0xd77420F73B4612a7A99DBA8c2AFd30a1886b0344" + ~address:"0xd77420f73b4612a7a99dba8c2afd30a1886b0344" ~signature:"run()" () in diff --git a/etherlink/tezt/tests/evm_sequencer.ml b/etherlink/tezt/tests/evm_sequencer.ml index 8f7b695b2be9a780d828dee305eb7eedabda6ff9..dc9a594443706d1c7d09f6ce173c373a9c002d18 100644 --- a/etherlink/tezt/tests/evm_sequencer.ml +++ b/etherlink/tezt/tests/evm_sequencer.ml @@ -8075,7 +8075,8 @@ let test_trace_delegate_call = sequencer in Check.( - JSON.(top_call |-> "to" |> as_string = delegator_address) + JSON.( + top_call |-> "to" |> as_string = String.lowercase_ascii delegator_address) string ~error_msg:"Top call should have been traced as coming from %R but was %L") ; Check.( @@ -8084,11 +8085,15 @@ let test_trace_delegate_call = ~error_msg:"Top call should have some subcalls") ; let delegatecall = JSON.(top_call |-> "calls" |> as_list |> List.hd) in Check.( - JSON.(delegatecall |-> "from" |> as_string = delegator_address) + JSON.( + delegatecall |-> "from" |> as_string + = String.lowercase_ascii delegator_address) string ~error_msg:"Delegate call should be traced as coming from %R but was %L") ; Check.( - JSON.(delegatecall |-> "to" |> as_string = delegated_address) + JSON.( + delegatecall |-> "to" |> as_string + = String.lowercase_ascii delegated_address) string ~error_msg: "Delegate call should be traced as going to delegated contract %R but \ @@ -8767,7 +8772,9 @@ let test_trace_transaction_calltracer_deposit = unit let test_miner = - let sequencer_pool_address = "0x8aaD6553Cf769Aa7b89174bE824ED0e53768ed70" in + let sequencer_pool_address = + String.lowercase_ascii "0x8aaD6553Cf769Aa7b89174bE824ED0e53768ed70" + in register_all ~__FILE__ ~tags:["evm"; "miner"; "coinbase"] @@ -8775,7 +8782,7 @@ let test_miner = ~sequencer_pool_address @@ fun {sequencer; evm_version; _} _protocol -> let*@ block = Rpc.get_block_by_number ~block:"latest" sequencer in - Check.((block.miner = sequencer_pool_address) string) + Check.((String.lowercase_ascii block.miner = sequencer_pool_address) string) ~error_msg: "Block miner should be the sequencer pool address, expected %R got %L" ; (* We deploy a contract that stores the block coinbase in its storage, and @@ -8801,7 +8808,10 @@ let test_miner = ~method_call:"getStorageCoinbase()" () in - Check.((String.trim storage_coinbase = sequencer_pool_address) string) + Check.( + (String.lowercase_ascii @@ String.trim storage_coinbase + = sequencer_pool_address) + string) ~error_msg: "Stored coinbase should be the sequencer pool address, expected %R got %L" ; let* view_coinbase = @@ -8812,7 +8822,10 @@ let test_miner = ~method_call:"getStorageCoinbase()" () in - Check.((String.trim view_coinbase = sequencer_pool_address) string) + Check.( + (String.lowercase_ascii @@ String.trim view_coinbase + = sequencer_pool_address) + string) ~error_msg: "Viewed coinbase should be the sequencer pool address, expected %R got %L" ; @@ -10452,11 +10465,11 @@ let test_tx_pool_replacing_transactions_on_limit () = in let txpool_content () = let*@ pending, queued = Rpc.txpool_content sequencer in - let sender = sender.address in + let sender = String.lowercase_ascii sender.address in let pending = List.find_map (fun Rpc.{address; transactions} -> - if address = sender then + if String.lowercase_ascii address = sender then Some (List.map fst transactions |> List.sort compare) else None) pending @@ -10464,7 +10477,7 @@ let test_tx_pool_replacing_transactions_on_limit () = let queued = List.find_map (fun Rpc.{address; transactions} -> - if address = sender then + if String.lowercase_ascii address = sender then Some (List.map fst transactions |> List.sort compare) else None) queued @@ -11237,6 +11250,7 @@ let test_websocket_logs_event = ~bin:erc20.bin) sequencer in + let address = String.lowercase_ascii address in let transfer_event_topic = let h = Tezos_crypto.Hacl.Hash.Keccak_256.digest