Skip to content

Commit 6ed32d9

Browse files
committed
Incorporate emit_log
1 parent cc20163 commit 6ed32d9

File tree

7 files changed

+433
-8
lines changed

7 files changed

+433
-8
lines changed

src/codegen/events/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
mod polkadot;
44
mod solana;
5+
mod stylus;
56

67
use crate::codegen::cfg::ControlFlowGraph;
78
use crate::codegen::events::polkadot::PolkadotEventEmitter;
89
use crate::codegen::events::solana::SolanaEventEmitter;
10+
use crate::codegen::events::stylus::StylusEventEmitter;
911
use crate::codegen::vartable::Vartable;
1012
use crate::codegen::Options;
1113
use crate::sema::ast;
@@ -53,6 +55,6 @@ pub(super) fn new_event_emitter<'a>(
5355

5456
Target::Soroban => todo!(),
5557

56-
Target::Stylus => todo!(),
58+
Target::Stylus => Box::new(StylusEventEmitter { args, ns, event_no }),
5759
}
5860
}

src/codegen/events/stylus.rs

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
// smoelius: This file is a slight variant of ../polkadot.rs.
4+
5+
use std::vec;
6+
7+
use crate::codegen::cfg::{ControlFlowGraph, Instr};
8+
use crate::codegen::encoding::abi_encode;
9+
use crate::codegen::events::EventEmitter;
10+
use crate::codegen::expression::expression;
11+
use crate::codegen::vartable::Vartable;
12+
use crate::codegen::{Builtin, Expression, Options};
13+
use crate::sema::ast::{self, Function, Namespace, RetrieveType, Type};
14+
use ink_env::hash::{CryptoHash, Keccak256};
15+
use solang_parser::pt;
16+
17+
/// Implements [EventEmitter] to handle the emission of events on Stylus.
18+
pub(super) struct StylusEventEmitter<'a> {
19+
/// Arguments passed to the event
20+
pub(super) args: &'a [ast::Expression],
21+
pub(super) ns: &'a Namespace,
22+
pub(super) event_no: usize,
23+
}
24+
25+
impl EventEmitter for StylusEventEmitter<'_> {
26+
fn selector(&self, _emitting_contract_no: usize) -> Vec<u8> {
27+
let signature = self.ns.events[self.event_no].signature.as_bytes();
28+
let mut buf = [0; 32];
29+
<Keccak256 as CryptoHash>::hash(signature, &mut buf);
30+
buf.into()
31+
}
32+
33+
fn emit(
34+
&self,
35+
contract_no: usize,
36+
func: &Function,
37+
cfg: &mut ControlFlowGraph,
38+
vartab: &mut Vartable,
39+
opt: &Options,
40+
) {
41+
let loc = pt::Loc::Builtin;
42+
let event = &self.ns.events[self.event_no];
43+
let hash_len = Box::new(Expression::NumberLiteral {
44+
loc,
45+
ty: Type::Uint(32),
46+
value: 32.into(),
47+
});
48+
let (mut data, mut topics) = (Vec::new(), Vec::new());
49+
50+
// Events that are not anonymous always have themselves as a topic.
51+
// This is static and can be calculated at compile time.
52+
if !event.anonymous {
53+
topics.push(Expression::AllocDynamicBytes {
54+
loc,
55+
ty: Type::Slice(Type::Uint(8).into()),
56+
size: hash_len.clone(),
57+
initializer: self.selector(contract_no).into(),
58+
});
59+
};
60+
61+
for (ast_exp, field) in self.args.iter().zip(event.fields.iter()) {
62+
let value_exp = expression(ast_exp, cfg, contract_no, Some(func), self.ns, vartab, opt);
63+
let value_var = vartab.temp_anonymous(&value_exp.ty());
64+
let value = Expression::Variable {
65+
loc,
66+
ty: value_exp.ty(),
67+
var_no: value_var,
68+
};
69+
cfg.add(
70+
vartab,
71+
Instr::Set {
72+
loc,
73+
res: value_var,
74+
expr: value_exp,
75+
},
76+
);
77+
data.push(value.clone());
78+
79+
if !field.indexed {
80+
continue;
81+
}
82+
83+
let (value_encoded, size) = abi_encode(&loc, vec![value], self.ns, vartab, cfg, false);
84+
85+
vartab.new_dirty_tracker();
86+
let var_buffer = vartab.temp_anonymous(&Type::DynamicBytes);
87+
cfg.add(
88+
vartab,
89+
Instr::Set {
90+
loc,
91+
res: var_buffer,
92+
expr: value_encoded,
93+
},
94+
);
95+
let buffer = Expression::Variable {
96+
loc,
97+
ty: Type::DynamicBytes,
98+
var_no: var_buffer,
99+
};
100+
101+
let hash_topic_block = cfg.new_basic_block("hash_topic".into());
102+
let done_block = cfg.new_basic_block("done".into());
103+
let size_is_greater_than_hash_length = Expression::More {
104+
loc,
105+
signed: false,
106+
left: size.clone().into(),
107+
right: hash_len.clone(),
108+
};
109+
cfg.add(
110+
vartab,
111+
Instr::BranchCond {
112+
cond: size_is_greater_than_hash_length,
113+
true_block: hash_topic_block,
114+
false_block: done_block,
115+
},
116+
);
117+
118+
cfg.set_basic_block(hash_topic_block);
119+
cfg.add(
120+
vartab,
121+
Instr::WriteBuffer {
122+
buf: buffer.clone(),
123+
offset: Expression::NumberLiteral {
124+
loc,
125+
ty: Type::Uint(32),
126+
value: 0.into(),
127+
},
128+
value: Expression::Builtin {
129+
loc,
130+
tys: vec![Type::Bytes(32)],
131+
kind: Builtin::Keccak256,
132+
args: vec![buffer.clone()],
133+
},
134+
},
135+
);
136+
vartab.set_dirty(var_buffer);
137+
cfg.add(vartab, Instr::Branch { block: done_block });
138+
139+
cfg.set_basic_block(done_block);
140+
cfg.set_phis(done_block, vartab.pop_dirty_tracker());
141+
142+
topics.push(buffer);
143+
}
144+
145+
let data = self
146+
.args
147+
.iter()
148+
.map(|e| expression(e, cfg, contract_no, Some(func), self.ns, vartab, opt))
149+
.collect::<Vec<_>>();
150+
let encoded_data = if data.is_empty() {
151+
Expression::AllocDynamicBytes {
152+
loc,
153+
ty: Type::DynamicBytes,
154+
size: Expression::NumberLiteral {
155+
loc,
156+
ty: Type::Uint(32),
157+
value: 0.into(),
158+
}
159+
.into(),
160+
initializer: Vec::new().into(),
161+
}
162+
} else {
163+
abi_encode(&loc, data, self.ns, vartab, cfg, false).0
164+
};
165+
166+
cfg.add(
167+
vartab,
168+
Instr::EmitEvent {
169+
event_no: self.event_no,
170+
data: encoded_data,
171+
topics,
172+
},
173+
);
174+
}
175+
}

src/emit/binary.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,9 @@ pub struct Binary<'a> {
175175
// `scratch_len` and `scratch` are used by Polkadot.
176176
pub(crate) scratch_len: Option<GlobalValue<'a>>,
177177
pub(crate) scratch: Option<GlobalValue<'a>>,
178-
// `return_code` and `return_data_len` are used by Stylus.
178+
// `args`, `args_len`, `return_code`, and `return_data_len` are used by Stylus.
179+
pub(crate) args: Option<GlobalValue<'a>>,
180+
pub(crate) args_len: Option<GlobalValue<'a>>,
179181
pub(crate) return_code: Option<GlobalValue<'a>>,
180182
pub(crate) return_data_len: Option<GlobalValue<'a>>,
181183
pub(crate) parameters: Option<PointerValue<'a>>,
@@ -453,6 +455,8 @@ impl<'a> Binary<'a> {
453455
calldata_len,
454456
scratch: None,
455457
scratch_len: None,
458+
args: None,
459+
args_len: None,
456460
return_code: None,
457461
return_data_len: None,
458462
parameters: None,

src/emit/stylus/mod.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,31 @@ impl StylusTarget {
3535
None,
3636
);
3737

38+
let args = bin.module.add_global(
39+
bin.context.i8_type().ptr_type(AddressSpace::default()),
40+
Some(AddressSpace::default()),
41+
"args",
42+
);
43+
args.set_linkage(Linkage::Internal);
44+
args.set_initializer(
45+
&bin.context
46+
.i8_type()
47+
.ptr_type(AddressSpace::default())
48+
.get_undef(),
49+
);
50+
51+
bin.args = Some(args);
52+
53+
let args_len = bin.module.add_global(
54+
bin.context.i32_type(),
55+
Some(AddressSpace::default()),
56+
"args_len",
57+
);
58+
args_len.set_linkage(Linkage::Internal);
59+
args_len.set_initializer(&bin.context.i32_type().get_undef());
60+
61+
bin.args_len = Some(args_len);
62+
3863
let return_code = bin.module.add_global(
3964
context.i32_type(),
4065
Some(AddressSpace::default()),
@@ -69,6 +94,7 @@ impl StylusTarget {
6994
"call_contract",
7095
"contract_address",
7196
"delegate_call_contract",
97+
"emit_log",
7298
"log_txt",
7399
"msg_reentrant",
74100
"msg_sender",
@@ -159,6 +185,7 @@ impl StylusTarget {
159185
u64_val,
160186
u8_ptr
161187
);
188+
external!("emit_log", void_type, u8_ptr, u32_val, u32_val);
162189
external!("log_txt", void_type, u8_ptr, u32_val);
163190
external!("msg_reentrant", i32_type);
164191
external!("msg_sender", void_type, u8_ptr);
@@ -191,6 +218,7 @@ impl StylusTarget {
191218
.fn_type(&[bin.context.i32_type().into()], false);
192219
let func = bin.module.add_function("user_entrypoint", ty, None);
193220
let (args, args_len) = self.public_function_prelude(bin, func);
221+
self.assign_args_globals(bin, args, args_len);
194222
// smoelius: FIXME: zero
195223
let zero = bin.context.custom_width_int_type(256).const_zero();
196224
let args = &[
@@ -216,4 +244,18 @@ impl StylusTarget {
216244
let return_code: &dyn BasicValue = &return_code;
217245
bin.builder.build_return(Some(return_code)).unwrap();
218246
}
247+
248+
fn assign_args_globals<'a>(
249+
&self,
250+
bin: &Binary<'a>,
251+
args: PointerValue<'a>,
252+
args_len: IntValue<'a>,
253+
) {
254+
bin.builder
255+
.build_store(bin.args.unwrap().as_pointer_value(), args)
256+
.unwrap();
257+
bin.builder
258+
.build_store(bin.args_len.unwrap().as_pointer_value(), args_len)
259+
.unwrap();
260+
}
219261
}

src/emit/stylus/storage.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,8 @@ impl StorageSlot for StylusTarget {
641641
self.storage_store_slot(bin, ty, slot, slot_ptr, dest, function)
642642
}
643643
_ => {
644+
// dbg!(ty);
645+
644646
bin.builder.build_store(slot_ptr, *slot).unwrap();
645647

646648
let dest = if dest.is_int_value() {

0 commit comments

Comments
 (0)