@@ -12,18 +12,22 @@ use {
12
12
fil_actors_runtime:: runtime:: Runtime ,
13
13
} ;
14
14
15
- #[ inline]
16
15
pub fn extcodesize (
17
16
_state : & mut ExecutionState ,
18
17
system : & System < impl Runtime > ,
19
18
addr : U256 ,
20
19
) -> Result < U256 , StatusCode > {
21
- // TODO we're fetching the entire block here just to get its size. We should instead use
20
+ // TODO (M2.2) we're fetching the entire block here just to get its size. We should instead use
22
21
// the ipld::block_stat syscall, but the Runtime nor the Blockstore expose it.
23
22
// Tracked in https://github.com/filecoin-project/ref-fvm/issues/867
24
- let len = get_evm_bytecode_cid ( system. rt , addr)
25
- . and_then ( |cid| get_evm_bytecode ( system. rt , & cid) )
26
- . map ( |bytecode| bytecode. len ( ) ) ?;
23
+ let len = match get_cid_type ( system. rt , addr) {
24
+ ContractType :: EVM ( addr) => {
25
+ get_evm_bytecode ( system. rt , & addr) . map ( |bytecode| bytecode. len ( ) ) ?
26
+ }
27
+ ContractType :: Native ( _) => 1 ,
28
+ // account and not found are flattened to 0 size
29
+ _ => 0 ,
30
+ } ;
27
31
28
32
Ok ( len. into ( ) )
29
33
}
@@ -33,8 +37,16 @@ pub fn extcodehash(
33
37
system : & System < impl Runtime > ,
34
38
addr : U256 ,
35
39
) -> Result < U256 , StatusCode > {
36
- let cid = get_evm_bytecode_cid ( system. rt , addr) ?;
37
- let digest = cid. hash ( ) . digest ( ) ;
40
+ let addr = match get_cid_type ( system. rt , addr) {
41
+ ContractType :: EVM ( a) => Ok ( a) ,
42
+ _ => Err ( StatusCode :: InvalidArgument (
43
+ "Cannot invoke EXTCODEHASH for non-EVM actor." . to_string ( ) ,
44
+ ) ) ,
45
+ } ?;
46
+ let bytecode_cid = get_evm_bytecode_cid ( system. rt , & addr) ?;
47
+
48
+ let digest = bytecode_cid. hash ( ) . digest ( ) ;
49
+
38
50
// Take the first 32 bytes of the Multihash
39
51
let digest_len = digest. len ( ) . min ( 32 ) ;
40
52
Ok ( digest[ ..digest_len] . into ( ) )
@@ -48,40 +60,55 @@ pub fn extcodecopy(
48
60
data_offset : U256 ,
49
61
size : U256 ,
50
62
) -> Result < ( ) , StatusCode > {
51
- let bytecode =
52
- get_evm_bytecode_cid ( system. rt , addr) . and_then ( |cid| get_evm_bytecode ( system. rt , & cid) ) ?;
63
+ let bytecode = match get_cid_type ( system. rt , addr) {
64
+ ContractType :: EVM ( addr) => get_evm_bytecode ( system. rt , & addr) ?,
65
+ ContractType :: NotFound | ContractType :: Account => Vec :: new ( ) ,
66
+ // calling EXTCODECOPY on native actors results with a single byte 0xFE which solidtiy uses for its `assert`/`throw` methods
67
+ // and in general invalid EVM bytecode
68
+ _ => vec ! [ 0xFE ] ,
69
+ } ;
53
70
54
71
copy_to_memory ( & mut state. memory , dest_offset, size, data_offset, bytecode. as_slice ( ) , true )
55
72
}
56
73
57
- pub fn get_evm_bytecode_cid ( rt : & impl Runtime , addr : U256 ) -> Result < Cid , StatusCode > {
58
- let addr : EthAddress = addr . into ( ) ;
59
- let addr : Address = addr . try_into ( ) ? ;
60
- // TODO: just return none in most of these cases?
61
- let actor_id = rt . resolve_address ( & addr ) . ok_or_else ( || {
62
- StatusCode :: InvalidArgument ( "failed to resolve address" . to_string ( ) )
63
- // TODO better error code
64
- } ) ? ;
74
+ # [ derive ( Debug ) ]
75
+ pub enum ContractType {
76
+ /// EVM Address and the CID of the actor (not the bytecode)
77
+ EVM ( Address ) ,
78
+ Native ( Cid ) ,
79
+ Account ,
80
+ NotFound ,
81
+ }
65
82
66
- let evm_cid = rt. get_code_cid_for_type ( Type :: EVM ) ;
67
- let target_cid = rt. get_actor_code_cid ( & actor_id) ;
83
+ /// Resolves an address to the address type
84
+ pub fn get_cid_type ( rt : & impl Runtime , addr : U256 ) -> ContractType {
85
+ let addr: EthAddress = addr. into ( ) ;
68
86
69
- if Some ( evm_cid) != target_cid {
70
- return Err ( StatusCode :: InvalidArgument (
71
- "cannot invoke EXTCODESIZE for non-EVM actor" . to_string ( ) ,
72
- ) ) ; // TODO better error code
73
- }
87
+ addr. try_into ( )
88
+ . ok ( ) // into filecoin address
89
+ . and_then ( |addr| rt. resolve_address ( & addr) ) // resolve actor id
90
+ . and_then ( |id| rt. get_actor_code_cid ( & id) . map ( |cid| ( id, cid) ) ) // resolve code cid
91
+ . map ( |( id, cid) | match rt. resolve_builtin_actor_type ( & cid) {
92
+ // TODO part of current account abstraction hack where embryos are accounts
93
+ Some ( Type :: Account | Type :: Embryo ) => ContractType :: Account ,
94
+ Some ( Type :: EVM ) => ContractType :: EVM ( Address :: new_id ( id) ) ,
95
+ // remaining builtin actors are native
96
+ _ => ContractType :: Native ( cid) ,
97
+ } )
98
+ . unwrap_or ( ContractType :: NotFound )
99
+ }
74
100
75
- let cid = rt
76
- . send ( & addr , crate :: Method :: GetBytecode as u64 , Default :: default ( ) , TokenAmount :: zero ( ) ) ?
77
- . deserialize ( ) ? ;
78
- Ok ( cid )
101
+ pub fn get_evm_bytecode_cid ( rt : & impl Runtime , addr : & Address ) -> Result < Cid , ActorError > {
102
+ Ok ( rt
103
+ . send ( addr , crate :: Method :: GetBytecode as u64 , Default :: default ( ) , TokenAmount :: zero ( ) ) ?
104
+ . deserialize ( ) ? )
79
105
}
80
106
81
- pub fn get_evm_bytecode ( rt : & impl Runtime , cid : & Cid ) -> Result < Vec < u8 > , StatusCode > {
107
+ pub fn get_evm_bytecode ( rt : & impl Runtime , addr : & Address ) -> Result < Vec < u8 > , StatusCode > {
108
+ let cid = get_evm_bytecode_cid ( rt, addr) ?;
82
109
let raw_bytecode = rt
83
110
. store ( )
84
- . get ( cid) // TODO this is inefficient; should call stat here.
111
+ . get ( & cid) // TODO this is inefficient; should call stat here.
85
112
. map_err ( |e| StatusCode :: InternalError ( format ! ( "failed to get bytecode block: {}" , & e) ) ) ?
86
113
. ok_or_else ( || ActorError :: not_found ( "bytecode block not found" . to_string ( ) ) ) ?;
87
114
Ok ( raw_bytecode)
0 commit comments