Skip to content

Commit 2aa6290

Browse files
committed
Add support for events and indexed fields.
This adds two new attributes: `#[event]` and `#[indexed]`. The `#[event]` attribute marks a struct or enum as an event that can be emitted by a contract. The `#[indexed]` attribute can be applied to fields within structs that are attributed with `#[event]`. This is particularly useful for event structs, allowing for efficient filtering and searching of emitted events based on the values of these fields. When using this attribute, the indexed fields must be applied sequentially to the initial set of fields in a struct. This attribute can only be applied to fields whose type is an exact size ABI type. The exact size ABI types include: - `bool` - `u8`, `u16`, `u32`, `u64`, `u256` - `numeric` - `b256` - `str[N]` - Tuples containing only exact size types - Structs containing only exact size types - Arrays of exact size types with a literal length - Type aliases to exact size types Additionally it causes the event types to be included in the JSON ABI representation for the contract. ```sway struct MyEventStruct { #[indexed] id: u64, sender: Identity, } enum MyEventEnum { A: (), B: (), } ``` Additionally this updates the JSON ABI to emit an `offset` for indexed fields.
1 parent cb6eee1 commit 2aa6290

File tree

58 files changed

+2488
-305
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+2488
-305
lines changed

Cargo.lock

Lines changed: 1182 additions & 156 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ members = [
2020
"sway-utils",
2121
"swayfmt",
2222
"test",
23+
"test/src/sdk-harness",
2324
]
2425
exclude = ["examples/*", "swayfmt/test_macros", "forc-test/test_data"]
2526

@@ -74,7 +75,7 @@ sway-ir-macros = { path = "sway-ir/sway-ir-macros", version = "0.69.1" }
7475
#
7576

7677
# Dependencies from the `fuel-abi-types` repository:
77-
fuel-abi-types = "0.15.2"
78+
fuel-abi-types = { path = "../fuel-abi-types/", version = "0.15.2" }
7879

7980
# Dependencies from the `fuel-core` repository:
8081
#
@@ -89,9 +90,9 @@ fuel-core-types = { version = "0.44", default-features = false }
8990

9091
# Dependencies from the `fuels-rs` repository:
9192

92-
fuels = "0.74"
93-
fuels-core = "0.74"
94-
fuels-accounts = "0.74"
93+
fuels = { path = "../fuels-rs/packages/fuels", version = "0.75" }
94+
fuels-core = { path = "../fuels-rs/packages/fuels-core", version = "0.75" }
95+
fuels-accounts = { path = "../fuels-rs/packages/fuels-accounts", version = "0.75" }
9596

9697
# Dependencies from the `fuel-vm` repository:
9798
fuel-asm = "0.62"

docs/book/src/reference/attributes.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ Below is the list of attributes supported by the Sway compiler, ordered alphabet
1010
- [Deprecated](#deprecated)
1111
- [Error](#error)
1212
- [Error Type](#error-type)
13+
- [Event](#event--indexed)
1314
- [Fallback](#fallback)
15+
- [Indexed](#event--indexed)
1416
- [Inline](#inline)
1517
- [Payable](#payable)
1618
- [Storage](#payable)
@@ -118,6 +120,43 @@ enum SomeErrors {
118120

119121
All variants of an error type enum must be annotated with the [`#[error]` attribute](#error). Error type enums are meant to be use in `panic` expressions for rich error reporting.
120122

123+
## Event / Indexed
124+
125+
The `#[event]` attribute marks a struct or enum as an event that can be emitted by a contract.
126+
127+
The `#[indexed]` attribute can be applied to fields within structs that are attributed with `#[event]`. This is particularly useful for event structs, allowing for efficient filtering and searching of emitted events based on the values of these fields.
128+
129+
When using this attribute, the indexed fields must be applied sequentially to the initial set of fields in a struct.
130+
131+
This attribute can only be applied to fields whose type is an exact size ABI type. The exact size ABI types include:
132+
133+
- `bool`
134+
- `u8`, `u16`, `u32`, `u64`, `u256`
135+
- `numeric`
136+
- `b256`
137+
- `str[N]`
138+
- Tuples containing only exact size types
139+
- Structs containing only exact size types
140+
- Arrays of exact size types with a literal length
141+
- Type aliases to exact size types
142+
143+
Additionally it causes the event types to be included in the JSON ABI representation for the contract.
144+
145+
```sway
146+
#[event]
147+
struct MyEventStruct {
148+
#[indexed]
149+
id: u64,
150+
sender: Identity,
151+
}
152+
153+
#[event]
154+
enum MyEventEnum {
155+
A: (),
156+
B: (),
157+
}
158+
```
159+
121160
## Fallback
122161

123162
The `#[fallback]` attribute makes the compiler use the marked function as the contract call fallback function. This means that, when a contract method is called, and the contract method selection fails, the fallback function will be called instead.

sway-ast/src/attribute.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ pub const TRACE_ALWAYS_ARG_NAME: &str = "always";
6161
pub const ABI_NAME_ATTRIBUTE_NAME: &str = "abi_name";
6262
pub const ABI_NAME_NAME_ARG_NAME: &str = "name";
6363

64+
pub const EVENT_ATTRIBUTE_NAME: &str = "event";
65+
pub const INDEXED_ATTRIBUTE_NAME: &str = "indexed";
66+
6467
pub const KNOWN_ATTRIBUTE_NAMES: &[&str] = &[
6568
STORAGE_ATTRIBUTE_NAME,
6669
DOC_COMMENT_ATTRIBUTE_NAME,
@@ -72,6 +75,8 @@ pub const KNOWN_ATTRIBUTE_NAMES: &[&str] = &[
7275
DEPRECATED_ATTRIBUTE_NAME,
7376
FALLBACK_ATTRIBUTE_NAME,
7477
ABI_NAME_ATTRIBUTE_NAME,
78+
EVENT_ATTRIBUTE_NAME,
79+
INDEXED_ATTRIBUTE_NAME,
7580
];
7681

7782
/// An attribute declaration. Attribute declaration

sway-core/src/abi_generation/fuel_abi.rs

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
ast_elements::type_parameter::GenericTypeParameter,
1616
language::ty::{TyFunctionDecl, TyProgram, TyProgramKind},
1717
transform::Attributes,
18-
Engines, PanicOccurrences, TypeId, TypeInfo,
18+
AbiEncodeSizeHint, Engines, PanicOccurrences, TypeId, TypeInfo,
1919
};
2020

2121
use super::abi_str::AbiStrContext;
@@ -900,15 +900,15 @@ impl TypeId {
900900

901901
let mut new_metadata_types_to_add =
902902
Vec::<program_abi::TypeMetadataDeclaration>::new();
903-
for x in decl.variants.iter() {
903+
for variant in decl.variants.iter() {
904904
generate_type_metadata_declaration(
905905
handler,
906906
ctx,
907907
engines,
908908
metadata_types,
909909
concrete_types,
910-
x.type_argument.initial_type_id(),
911-
x.type_argument.type_id(),
910+
variant.type_argument.initial_type_id(),
911+
variant.type_argument.type_id(),
912912
&mut new_metadata_types_to_add,
913913
)?;
914914
}
@@ -918,15 +918,15 @@ impl TypeId {
918918
let components = decl
919919
.variants
920920
.iter()
921-
.map(|x| {
921+
.map(|variant| {
922922
Ok(program_abi::TypeApplication {
923-
name: x.name.to_string(),
923+
name: variant.name.to_string(),
924924
type_id: program_abi::TypeId::Metadata(MetadataTypeId(
925-
x.type_argument.initial_type_id().index(),
925+
variant.type_argument.initial_type_id().index(),
926926
)),
927927
offset: None,
928-
error_message: x.attributes.error_message().cloned(),
929-
type_arguments: x
928+
error_message: variant.attributes.error_message().cloned(),
929+
type_arguments: variant
930930
.type_argument
931931
.initial_type_id()
932932
.get_abi_type_arguments(
@@ -935,7 +935,7 @@ impl TypeId {
935935
engines,
936936
metadata_types,
937937
concrete_types,
938-
x.type_argument.type_id(),
938+
variant.type_argument.type_id(),
939939
&mut new_metadata_types_to_add,
940940
)?,
941941
})
@@ -954,15 +954,15 @@ impl TypeId {
954954

955955
let mut new_metadata_types_to_add =
956956
Vec::<program_abi::TypeMetadataDeclaration>::new();
957-
for x in decl.fields.iter() {
957+
for field in decl.fields.iter() {
958958
generate_type_metadata_declaration(
959959
handler,
960960
ctx,
961961
engines,
962962
metadata_types,
963963
concrete_types,
964-
x.type_argument.initial_type_id(),
965-
x.type_argument.type_id(),
964+
field.type_argument.initial_type_id(),
965+
field.type_argument.type_id(),
966966
&mut new_metadata_types_to_add,
967967
)?;
968968
}
@@ -972,15 +972,30 @@ impl TypeId {
972972
let components = decl
973973
.fields
974974
.iter()
975-
.map(|x| {
975+
.scan(0u16, |field_offset, field| {
976+
field.attributes.indexed()?;
977+
let hint = engines
978+
.te()
979+
.get(field.type_argument.type_id())
980+
.abi_encode_size_hint(engines);
981+
let size = if let AbiEncodeSizeHint::Exact(sz) = hint {
982+
sz as u16
983+
} else {
984+
0
985+
};
986+
let offset = if size > 0 { Some(*field_offset) } else { None };
987+
*field_offset += size;
988+
Some((field, offset))
989+
})
990+
.map(|(field, offset)| {
976991
Ok(program_abi::TypeApplication {
977-
name: x.name.to_string(),
992+
name: field.name.to_string(),
978993
type_id: program_abi::TypeId::Metadata(MetadataTypeId(
979-
x.type_argument.initial_type_id().index(),
994+
field.type_argument.initial_type_id().index(),
980995
)),
981996
error_message: None,
982-
offset: None,
983-
type_arguments: x
997+
offset,
998+
type_arguments: field
984999
.type_argument
9851000
.initial_type_id()
9861001
.get_abi_type_arguments(
@@ -989,7 +1004,7 @@ impl TypeId {
9891004
engines,
9901005
metadata_types,
9911006
concrete_types,
992-
x.type_argument.type_id(),
1007+
field.type_argument.type_id(),
9931008
&mut new_metadata_types_to_add,
9941009
)?,
9951010
})
@@ -1024,6 +1039,7 @@ impl TypeId {
10241039
elem_ty.initial_type_id().index(),
10251040
)),
10261041
error_message: None,
1042+
offset: None,
10271043
type_arguments: elem_ty.initial_type_id().get_abi_type_arguments(
10281044
handler,
10291045
ctx,
@@ -1059,6 +1075,7 @@ impl TypeId {
10591075
elem_ty.initial_type_id().index(),
10601076
)),
10611077
error_message: None,
1078+
offset: None,
10621079
type_arguments: elem_ty.initial_type_id().get_abi_type_arguments(
10631080
handler,
10641081
ctx,
@@ -1101,6 +1118,7 @@ impl TypeId {
11011118
x.initial_type_id().index(),
11021119
)),
11031120
error_message: None,
1121+
offset: None,
11041122
type_arguments: x.initial_type_id().get_abi_type_arguments(
11051123
handler,
11061124
ctx,
@@ -1247,6 +1265,7 @@ impl TypeId {
12471265
arg.initial_type_id().index(),
12481266
)),
12491267
error_message: None,
1268+
offset: None,
12501269
type_arguments: arg.initial_type_id().get_abi_type_arguments(
12511270
handler,
12521271
ctx,
@@ -1294,6 +1313,7 @@ impl TypeId {
12941313
p.type_id.index(),
12951314
)),
12961315
error_message: None,
1316+
offset: None,
12971317
type_arguments: p.type_id.get_abi_type_arguments(
12981318
handler,
12991319
ctx,
@@ -1349,6 +1369,7 @@ impl TypeId {
13491369
p.type_id.index(),
13501370
)),
13511371
error_message: None,
1372+
offset: None,
13521373
type_arguments: p.type_id.get_abi_type_arguments(
13531374
handler,
13541375
ctx,

sway-core/src/asm_generation/fuel/fuel_asm_builder.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,8 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> {
405405
log_val,
406406
log_ty,
407407
log_id,
408-
} => self.compile_log(instr_val, log_val, log_ty, log_id),
408+
log_data,
409+
} => self.compile_log(instr_val, log_val, log_ty, log_id, log_data),
409410
FuelVmInstruction::ReadRegister(reg) => {
410411
self.compile_read_register(instr_val, reg);
411412
Ok(())
@@ -1684,18 +1685,33 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> {
16841685
log_val: &Value,
16851686
log_ty: &Type,
16861687
log_id: &Value,
1688+
log_data: &Option<LogEventData>,
16871689
) -> Result<(), CompileError> {
16881690
let owning_span = self.md_mgr.val_to_span(self.context, *instr_val);
16891691
let log_val_reg = self.value_to_register(log_val)?;
16901692
let log_id_reg = self.value_to_register(log_id)?;
1693+
let log_metadata_reg = if let Some(log_data) = log_data {
1694+
let encoded = log_data.encoded();
1695+
let reg = self.reg_seqr.next();
1696+
self.immediate_to_reg(
1697+
encoded,
1698+
reg.clone(),
1699+
None,
1700+
"load log event metadata",
1701+
owning_span.clone(),
1702+
);
1703+
reg
1704+
} else {
1705+
VirtualRegister::Constant(ConstantRegister::Zero)
1706+
};
16911707

16921708
if !log_ty.is_ptr(self.context) {
16931709
self.cur_bytecode.push(Op {
16941710
owning_span,
16951711
opcode: Either::Left(VirtualOp::LOG(
16961712
log_val_reg,
16971713
log_id_reg,
1698-
VirtualRegister::Constant(ConstantRegister::Zero),
1714+
log_metadata_reg,
16991715
VirtualRegister::Constant(ConstantRegister::Zero),
17001716
)),
17011717
comment: "log non-pointer value".into(),
@@ -1732,7 +1748,7 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> {
17321748
self.cur_bytecode.push(Op {
17331749
owning_span,
17341750
opcode: Either::Left(VirtualOp::LOGD(
1735-
VirtualRegister::Constant(ConstantRegister::Zero),
1751+
log_metadata_reg.clone(),
17361752
log_id_reg,
17371753
ptr_reg,
17381754
size_reg,
@@ -1754,7 +1770,7 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> {
17541770
self.cur_bytecode.push(Op {
17551771
owning_span: owning_span.clone(),
17561772
opcode: Either::Left(VirtualOp::LOGD(
1757-
VirtualRegister::Constant(ConstantRegister::Zero),
1773+
log_metadata_reg,
17581774
log_id_reg.clone(),
17591775
log_val_reg.clone(),
17601776
size_reg,

0 commit comments

Comments
 (0)