Skip to content

Commit 6d73502

Browse files
authored
EVM: propagate return data when contract creation fails (#1291)
feat: propegate return data when contract creation fails And clear the return data otherwise.
1 parent 23f0116 commit 6d73502

File tree

8 files changed

+156
-47
lines changed

8 files changed

+156
-47
lines changed

actors/evm/src/interpreter/instructions/lifecycle.rs

Lines changed: 116 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use fil_actors_runtime::ActorError;
44
use fil_actors_runtime::EAM_ACTOR_ADDR;
55
use fil_actors_runtime::{deserialize_block, extract_send_result};
66
use fvm_ipld_encoding::ipld_block::IpldBlock;
7+
use fvm_ipld_encoding::BytesDe;
78
use fvm_shared::sys::SendFlags;
89
use fvm_shared::MethodNum;
910
use fvm_shared::METHOD_SEND;
@@ -23,32 +24,32 @@ use {
2324
pub fn create(
2425
state: &mut ExecutionState,
2526
system: &mut System<impl Runtime>,
26-
value: U256,
27+
endowment: U256,
2728
offset: U256,
2829
size: U256,
2930
) -> Result<U256, ActorError> {
3031
if system.readonly {
3132
return Err(ActorError::read_only("create called while read-only".into()));
3233
}
34+
state.return_data = Vec::new();
3335

34-
let ExecutionState { stack: _, memory, .. } = state;
35-
36-
let value = TokenAmount::from(&value);
37-
if value > system.rt.current_balance() {
38-
return Ok(U256::zero());
39-
}
40-
let input_region = get_memory_region(memory, offset, size)?;
36+
let input_region = get_memory_region(&mut state.memory, offset, size)?;
4137

4238
let input_data = if let Some(MemoryRegion { offset, size }) = input_region {
43-
&memory[offset..][..size.get()]
39+
&state.memory[offset..][..size.get()]
4440
} else {
4541
&[]
4642
};
4743

4844
// We increment the nonce earlier than in the EVM. See the comment in `create2` for details.
49-
let nonce = system.increment_nonce();
50-
let params = eam::CreateParams { code: input_data.to_vec(), nonce };
51-
create_init(system, IpldBlock::serialize_cbor(&params)?, eam::CREATE_METHOD_NUM, value)
45+
let params = eam::CreateParams { code: input_data.to_vec(), nonce: system.nonce };
46+
create_common(
47+
state,
48+
system,
49+
IpldBlock::serialize_cbor(&params)?,
50+
eam::CREATE_METHOD_NUM,
51+
endowment,
52+
)
5253
}
5354

5455
pub fn create2(
@@ -63,25 +64,47 @@ pub fn create2(
6364
return Err(ActorError::read_only("create2 called while read-only".into()));
6465
}
6566

66-
let ExecutionState { stack: _, memory, .. } = state;
67-
68-
let endowment = TokenAmount::from(&endowment);
69-
if endowment > system.rt.current_balance() {
70-
return Ok(U256::zero());
71-
}
72-
73-
let input_region = get_memory_region(memory, offset, size)?;
67+
let input_region = get_memory_region(&mut state.memory, offset, size)?;
7468

7569
// BE encoded array
7670
let salt: [u8; 32] = salt.into();
7771

7872
let input_data = if let Some(MemoryRegion { offset, size }) = input_region {
79-
&memory[offset..][..size.get()]
73+
&state.memory[offset..][..size.get()]
8074
} else {
8175
&[]
8276
};
8377
let params = eam::Create2Params { code: input_data.to_vec(), salt };
8478

79+
create_common(
80+
state,
81+
system,
82+
IpldBlock::serialize_cbor(&params)?,
83+
eam::CREATE2_METHOD_NUM,
84+
endowment,
85+
)
86+
}
87+
88+
/// call into Ethereum Address Manager to make the new account
89+
#[inline]
90+
fn create_common(
91+
state: &mut ExecutionState,
92+
system: &mut System<impl Runtime>,
93+
params: Option<IpldBlock>,
94+
method: MethodNum,
95+
endowment: U256,
96+
) -> Result<U256, ActorError> {
97+
// First, we clear the return data. We want to do this even if we, e.g., fail due to the
98+
// endowment.
99+
state.return_data = Vec::new();
100+
101+
// Then we explicitly check the endowment. We could just try and deal with the error, but then
102+
// we'd need to add some logic for decrementing the nonce. It's easier to check up-front.
103+
let endowment = TokenAmount::from(&endowment);
104+
if endowment > system.rt.current_balance() {
105+
return Ok(U256::zero());
106+
}
107+
85108
// We increment the nonce earlier than in the EVM, but this is unlikely to cause issues:
86109
//
87110
// 1. Like the EVM, we increment the nonce on address conflict (effectively "skipping" the
@@ -93,30 +116,33 @@ pub fn create2(
93116
// stack depth. However, given that there are other ways to increment the nonce without
94117
// deploying a contract (e.g., 2), this shouldn't be an issue.
95118
system.increment_nonce();
96-
create_init(system, IpldBlock::serialize_cbor(&params)?, eam::CREATE2_METHOD_NUM, endowment)
97-
}
98119

99-
/// call into Ethereum Address Manager to make the new account
100-
#[inline]
101-
fn create_init(
102-
system: &mut System<impl Runtime>,
103-
params: Option<IpldBlock>,
104-
method: MethodNum,
105-
value: TokenAmount,
106-
) -> Result<U256, ActorError> {
107120
// Apply EIP-150
108121
let gas_limit = (63 * system.rt.gas_available()) / 64;
109122

110123
// send bytecode & params to EAM to generate the address and contract
111-
let ret =
112-
system.send(&EAM_ACTOR_ADDR, method, params, value, Some(gas_limit), SendFlags::default());
124+
let ret = system.send(
125+
&EAM_ACTOR_ADDR,
126+
method,
127+
params,
128+
endowment,
129+
Some(gas_limit),
130+
SendFlags::default(),
131+
);
113132

114133
Ok(match ret {
115134
Ok(eam_ret) => {
116135
let ret: eam::CreateReturn = deserialize_block(eam_ret)?;
117136
ret.eth_address.as_evm_word()
118137
}
119-
Err(_) => U256::zero(),
138+
Err(mut err) => {
139+
// Any non-empty return data here always comes from the constructor.
140+
if let Some(r) = err.take_data() {
141+
// As with CALL, ignore decode failures and fallback on returning the encoded value.
142+
state.return_data = r.deserialize().map(|BytesDe(d)| d).unwrap_or_else(|_| r.data);
143+
}
144+
U256::zero()
145+
}
120146
})
121147
}
122148

@@ -164,12 +190,13 @@ pub fn selfdestruct(
164190

165191
#[cfg(test)]
166192
mod tests {
167-
use crate::evm_unit_test;
168193
use crate::ext::eam;
194+
use crate::{evm_unit_test, EVM_CONTRACT_REVERTED};
169195

170196
use fil_actors_evm_shared::uints::U256;
171197
use fil_actors_runtime::EAM_ACTOR_ADDR;
172198
use fvm_ipld_encoding::ipld_block::IpldBlock;
199+
use fvm_ipld_encoding::BytesSer;
173200
use fvm_shared::address::Address as FilAddress;
174201
use fvm_shared::error::{ErrorNumber, ExitCode};
175202
use fvm_shared::sys::SendFlags;
@@ -267,16 +294,18 @@ mod tests {
267294
// the deed
268295
CREATE2;
269296
}
297+
m.state.return_data = b"deadbeef".to_vec(); // stale return data
270298
m.state.stack.push(U256::from(0xDEADBEEFu64)).unwrap(); // salt
271-
m.state.stack.push(U256::from(4)).unwrap(); // input size
272-
m.state.stack.push(U256::from(28)).unwrap(); // input offset
273-
m.state.stack.push(U256::from(1234)).unwrap(); // initial value
299+
m.state.stack.push(U256::from(4)).unwrap(); // input size
300+
m.state.stack.push(U256::from(28)).unwrap(); // input offset
301+
m.state.stack.push(U256::from(1234)).unwrap(); // initial value
274302
for _ in 0..4 {
275303
m.step().expect("execution step failed");
276304
}
277305
assert_eq!(m.state.stack.len(), 1);
278306
assert_eq!(m.state.stack.pop().unwrap(), ret_addr.as_evm_word());
279307
assert_eq!(m.system.nonce, 2);
308+
assert!(m.state.return_data.is_empty());
280309
};
281310
}
282311

@@ -466,6 +495,54 @@ mod tests {
466495
// the deed
467496
CREATE;
468497
}
498+
m.state.return_data = b"deadbeef".to_vec(); // stale return data
499+
m.state.stack.push(U256::from(4)).unwrap(); // input size
500+
m.state.stack.push(U256::from(28)).unwrap(); // input offset
501+
m.state.stack.push(U256::from(1234)).unwrap(); // initial value
502+
for _ in 0..4 {
503+
m.step().expect("execution step failed");
504+
}
505+
assert_eq!(m.state.stack.len(), 1);
506+
assert_eq!(m.state.stack.pop().unwrap(), U256::from(0));
507+
assert_eq!(m.system.nonce, 2);
508+
assert!(m.state.return_data.is_empty());
509+
};
510+
}
511+
512+
#[test]
513+
fn test_create_revert() {
514+
let revert_data = &b"foobar"[..];
515+
evm_unit_test! {
516+
(rt) {
517+
rt.set_balance(TokenAmount::from_atto(1_000_000));
518+
519+
let code = vec![0x01, 0x02, 0x03, 0x04];
520+
let nonce = 1;
521+
let create_params = eam::CreateParams { code, nonce };
522+
let create_return = BytesSer(revert_data);
523+
524+
rt.expect_gas_available(10_000_000_000);
525+
rt.expect_send(
526+
EAM_ACTOR_ADDR,
527+
eam::CREATE_METHOD_NUM,
528+
IpldBlock::serialize_cbor(&create_params).unwrap(),
529+
TokenAmount::from_atto(1234),
530+
Some(63 * 10_000_000_000 / 64),
531+
SendFlags::empty(),
532+
IpldBlock::serialize_cbor(&create_return).unwrap(),
533+
EVM_CONTRACT_REVERTED,
534+
None,
535+
);
536+
}
537+
(m) {
538+
// input data
539+
PUSH4; 0x01; 0x02; 0x03; 0x04;
540+
PUSH0;
541+
MSTORE;
542+
// the deed
543+
CREATE;
544+
}
545+
m.state.return_data = b"deadbeef".to_vec(); // stale return data
469546
m.state.stack.push(U256::from(4)).unwrap(); // input size
470547
m.state.stack.push(U256::from(28)).unwrap(); // input offset
471548
m.state.stack.push(U256::from(1234)).unwrap(); // initial value
@@ -475,6 +552,7 @@ mod tests {
475552
assert_eq!(m.state.stack.len(), 1);
476553
assert_eq!(m.state.stack.pop().unwrap(), U256::from(0));
477554
assert_eq!(m.system.nonce, 2);
555+
assert_eq!(m.state.return_data, revert_data)
478556
};
479557
}
480558

actors/evm/src/interpreter/system.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,9 @@ impl<'r, RT: Runtime> System<'r, RT> {
191191
})
192192
}
193193

194-
pub fn increment_nonce(&mut self) -> u64 {
194+
pub fn increment_nonce(&mut self) {
195195
self.saved_state_root = None;
196-
let nonce = self.nonce;
197196
self.nonce = self.nonce.checked_add(1).unwrap();
198-
nonce
199197
}
200198

201199
/// Transfers funds to the receiver. This doesn't bother saving/reloading state.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
608060405234801561001057600080fd5b5061048a806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80630876a11e1461003b5780631e1932941461006b575b600080fd5b6100556004803603810190610050919061019c565b61009b565b604051610062919061021d565b60405180910390f35b61008560048036038101906100809190610238565b6100de565b604051610092919061021d565b60405180910390f35b600082826040516100ab9061011b565b6100b59190610274565b8190604051809103906000f59050801580156100d5573d6000803e3d6000fd5b50905092915050565b6000816040516100ed9061011b565b6100f79190610274565b604051809103906000f080158015610113573d6000803e3d6000fd5b509050919050565b6101c58061029083390190565b600080fd5b6000819050919050565b6101408161012d565b811461014b57600080fd5b50565b60008135905061015d81610137565b92915050565b60008160030b9050919050565b61017981610163565b811461018457600080fd5b50565b60008135905061019681610170565b92915050565b600080604083850312156101b3576101b2610128565b5b60006101c18582860161014e565b92505060206101d285828601610187565b9150509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610207826101dc565b9050919050565b610217816101fc565b82525050565b6000602082019050610232600083018461020e565b92915050565b60006020828403121561024e5761024d610128565b5b600061025c84828501610187565b91505092915050565b61026e81610163565b82525050565b60006020820190506102896000830184610265565b9291505056fe608060405234801561001057600080fd5b506040516101c53803806101c583398181016040528101906100329190610099565b806000806101000a81548163ffffffff021916908360030b63ffffffff160217905550506100c6565b600080fd5b60008160030b9050919050565b61007681610060565b811461008157600080fd5b50565b6000815190506100938161006d565b92915050565b6000602082840312156100af576100ae61005b565b5b60006100bd84828501610084565b91505092915050565b60f1806100d46000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806333cf508014603757806335f46994146051575b600080fd5b603d6059565b6040516048919060a2565b60405180910390f35b6057606f565b005b60008060009054906101000a900460030b905090565b3373ffffffffffffffffffffffffffffffffffffffff16ff5b60008160030b9050919050565b609c816088565b82525050565b600060208201905060b560008301846095565b9291505056fea2646970667358221220515fddaf42d9a26595aaf38ed0775a03d845e2d847b5e94a23ec84f414bea90e64736f6c63430008110033a264697066735822122060b27608659f19cc27f02c0145ae6714d9886ccd9a56178f95522973c86d813864736f6c63430008110033
1+
608060405234801561000f575f80fd5b5061051a8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80630876a11e146100385780631e19329414610068575b5f80fd5b610052600480360381019061004d919061018a565b610098565b60405161005f9190610207565b60405180910390f35b610082600480360381019061007d9190610220565b6100d7565b60405161008f9190610207565b60405180910390f35b5f82826040516100a790610110565b6100b1919061025a565b8190604051809103905ff59050801580156100ce573d5f803e3d5ffd5b50905092915050565b5f816040516100e590610110565b6100ef919061025a565b604051809103905ff080158015610108573d5f803e3d5ffd5b509050919050565b6102718061027483390190565b5f80fd5b5f819050919050565b61013381610121565b811461013d575f80fd5b50565b5f8135905061014e8161012a565b92915050565b5f8160030b9050919050565b61016981610154565b8114610173575f80fd5b50565b5f8135905061018481610160565b92915050565b5f80604083850312156101a05761019f61011d565b5b5f6101ad85828601610140565b92505060206101be85828601610176565b9150509250929050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6101f1826101c8565b9050919050565b610201816101e7565b82525050565b5f60208201905061021a5f8301846101f8565b92915050565b5f602082840312156102355761023461011d565b5b5f61024284828501610176565b91505092915050565b61025481610154565b82525050565b5f60208201905061026d5f83018461024b565b9291505056fe608060405234801561000f575f80fd5b50604051610271380380610271833981810160405281019061003191906100d9565b5f8160030b1215610077576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161006e9061015e565b60405180910390fd5b805f806101000a81548163ffffffff021916908360030b63ffffffff1602179055505061017c565b5f80fd5b5f8160030b9050919050565b6100b8816100a3565b81146100c2575f80fd5b50565b5f815190506100d3816100af565b92915050565b5f602082840312156100ee576100ed61009f565b5b5f6100fb848285016100c5565b91505092915050565b5f82825260208201905092915050565b7f637265617465206661696c6564000000000000000000000000000000000000005f82015250565b5f610148600d83610104565b915061015382610114565b602082019050919050565b5f6020820190508181035f8301526101758161013c565b9050919050565b60e9806101885f395ff3fe6080604052348015600e575f80fd5b50600436106030575f3560e01c806333cf508014603457806335f4699414604e575b5f80fd5b603a6056565b60405160459190609c565b60405180910390f35b6054606a565b005b5f805f9054906101000a900460030b905090565b3373ffffffffffffffffffffffffffffffffffffffff16ff5b5f8160030b9050919050565b6096816083565b82525050565b5f60208201905060ad5f830184608f565b9291505056fea2646970667358221220010091073d3812b09a309a7b0030633391face9b5be6e3ee4fb2872d38c7b13664736f6c63430008150033a26469706673582212201f027bdadc64c1983cbb0ead43545c936db42976c5b87a4bb0eef19f6a5c269f64736f6c63430008150033
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
608060405234801561001057600080fd5b506040516101c53803806101c583398181016040528101906100329190610099565b806000806101000a81548163ffffffff021916908360030b63ffffffff160217905550506100c6565b600080fd5b60008160030b9050919050565b61007681610060565b811461008157600080fd5b50565b6000815190506100938161006d565b92915050565b6000602082840312156100af576100ae61005b565b5b60006100bd84828501610084565b91505092915050565b60f1806100d46000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806333cf508014603757806335f46994146051575b600080fd5b603d6059565b6040516048919060a2565b60405180910390f35b6057606f565b005b60008060009054906101000a900460030b905090565b3373ffffffffffffffffffffffffffffffffffffffff16ff5b60008160030b9050919050565b609c816088565b82525050565b600060208201905060b560008301846095565b9291505056fea2646970667358221220515fddaf42d9a26595aaf38ed0775a03d845e2d847b5e94a23ec84f414bea90e64736f6c63430008110033
1+
608060405234801561000f575f80fd5b50604051610271380380610271833981810160405281019061003191906100d9565b5f8160030b1215610077576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161006e9061015e565b60405180910390fd5b805f806101000a81548163ffffffff021916908360030b63ffffffff1602179055505061017c565b5f80fd5b5f8160030b9050919050565b6100b8816100a3565b81146100c2575f80fd5b50565b5f815190506100d3816100af565b92915050565b5f602082840312156100ee576100ed61009f565b5b5f6100fb848285016100c5565b91505092915050565b5f82825260208201905092915050565b7f637265617465206661696c6564000000000000000000000000000000000000005f82015250565b5f610148600d83610104565b915061015382610114565b602082019050919050565b5f6020820190508181035f8301526101758161013c565b9050919050565b60e9806101885f395ff3fe6080604052348015600e575f80fd5b50600436106030575f3560e01c806333cf508014603457806335f4699414604e575b5f80fd5b603a6056565b60405160459190609c565b60405180910390f35b6054606a565b005b5f805f9054906101000a900460030b905090565b3373ffffffffffffffffffffffffffffffffffffffff16ff5b5f8160030b9050919050565b6096816083565b82525050565b5f60208201905060ad5f830184608f565b9291505056fea2646970667358221220010091073d3812b09a309a7b0030633391face9b5be6e3ee4fb2872d38c7b13664736f6c63430008150033
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"storage":[{"astId":42,"contract":"tests/contracts/Lifecycle.sol:FactoryChild","label":"value","offset":0,"slot":"0","type":"t_int32"}],"types":{"t_int32":{"encoding":"inplace","label":"int32","numberOfBytes":"4"}}}
1+
{"storage":[{"astId":42,"contract":"Lifecycle.sol:FactoryChild","label":"value","offset":0,"slot":"0","type":"t_int32"}],"types":{"t_int32":{"encoding":"inplace","label":"int32","numberOfBytes":"4"}}}

0 commit comments

Comments
 (0)