Skip to content

Commit

Permalink
improve primitive upgrade check
Browse files Browse the repository at this point in the history
  • Loading branch information
remybar committed Jan 18, 2025
1 parent a2eb03c commit 0d63941
Show file tree
Hide file tree
Showing 2 changed files with 188 additions and 48 deletions.
160 changes: 127 additions & 33 deletions crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -361,15 +361,74 @@ fn test_introspect_upgrade() {
assert!(b.is_an_upgrade_of(@b));
}

#[test]
fn test_primitive_upgrade() {
let primitives = [
'bool', 'u8', 'u16', 'u32', 'usize', 'u64', 'u128', 'u256', 'i8', 'i16', 'i32', 'i64',
'i128', 'felt252', 'ClassHash', 'ContractAddress',
]
.span();

let mut allowed_upgrades: Span<(felt252, Span<felt252>)> = [
('bool', [].span()), ('u8', ['u16', 'u32', 'usize', 'u64', 'u128', 'felt252'].span()),
('u16', ['u32', 'usize', 'u64', 'u128', 'felt252'].span()),
('u32', ['usize', 'u64', 'u128', 'felt252'].span()),
('usize', ['u32', 'u64', 'u128', 'felt252'].span()), ('u64', ['u128', 'felt252'].span()),
('u128', ['felt252'].span()), ('u256', [].span()),
('i8', ['i16', 'i32', 'i64', 'i128', 'felt252'].span()),
('i16', ['i32', 'i64', 'i128', 'felt252'].span()),
('i32', ['i64', 'i128', 'felt252'].span()), ('i64', ['i128', 'felt252'].span()),
('i128', ['felt252'].span()), ('felt252', ['ClassHash', 'ContractAddress'].span()),
('ClassHash', ['felt252', 'ContractAddress'].span()),
('ContractAddress', ['felt252', 'ClassHash'].span()),
]
.span();

loop {
match allowed_upgrades.pop_front() {
Option::Some((
src, allowed,
)) => {
for dest in primitives {
let expected = if src == dest {
true
} else {
let allowed = *allowed;
let mut i = 0;

loop {
if i >= allowed.len() {
break false;
}

if *allowed.at(i) == *dest {
break true;
}

i += 1;
}
};

assert_eq!(
Ty::Primitive(*dest).is_an_upgrade_of(@Ty::Primitive(*src)), expected,
);
}
},
Option::None => { break; },
};
}
}

#[test]
fn test_struct_upgrade() {
let s = Struct {
name: 's', attrs: [
'one'
].span(), children: [
name: 's',
attrs: ['one'].span(),
children: [
Member { name: 'x', attrs: ['two'].span(), ty: Ty::Primitive('u8') },
Member { name: 'y', attrs: ['three'].span(), ty: Ty::Primitive('u16') }
].span()
Member { name: 'y', attrs: ['three'].span(), ty: Ty::Primitive('u16') },
]
.span(),
};

// different name
Expand All @@ -384,46 +443,67 @@ fn test_struct_upgrade() {

// member name changed
let mut upgraded = s;
upgraded.children = [
Member { name: 'new', attrs: ['two'].span(), ty: Ty::Primitive('u8') },
Member { name: 'y', attrs: ['three'].span(), ty: Ty::Primitive('u16') }
].span();
upgraded
.children =
[
Member { name: 'new', attrs: ['two'].span(), ty: Ty::Primitive('u8') },
Member { name: 'y', attrs: ['three'].span(), ty: Ty::Primitive('u16') },
]
.span();
assert!(!upgraded.is_an_upgrade_of(@s), "member name changed");

// member attr changed
let mut upgraded = s;
upgraded.children = [
Member { name: 'x', attrs: [].span(), ty: Ty::Primitive('u8') },
Member { name: 'y', attrs: ['three'].span(), ty: Ty::Primitive('u16') }
].span();
upgraded
.children =
[
Member { name: 'x', attrs: [].span(), ty: Ty::Primitive('u8') },
Member { name: 'y', attrs: ['three'].span(), ty: Ty::Primitive('u16') },
]
.span();
assert!(!upgraded.is_an_upgrade_of(@s), "member attr changed");

// allowed member change
let mut upgraded = s;
upgraded
.children =
[
Member { name: 'x', attrs: ['two'].span(), ty: Ty::Primitive('u16') },
Member { name: 'y', attrs: ['three'].span(), ty: Ty::Primitive('u16') },
]
.span();
assert!(upgraded.is_an_upgrade_of(@s), "allowed member change");

// wrong member change
let mut upgraded = s;
upgraded.children = [
Member { name: 'x', attrs: ['two'].span(), ty: Ty::Primitive('u8') },
Member { name: 'y', attrs: ['three'].span(), ty: Ty::Primitive('u8') }
].span();
upgraded
.children =
[
Member { name: 'x', attrs: ['two'].span(), ty: Ty::Primitive('u8') },
Member { name: 'y', attrs: ['three'].span(), ty: Ty::Primitive('u8') },
]
.span();
assert!(!upgraded.is_an_upgrade_of(@s), "wrong member change");

// new member
let mut upgraded = s;
upgraded.children = [
Member { name: 'x', attrs: ['two'].span(), ty: Ty::Primitive('u8') },
Member { name: 'y', attrs: ['three'].span(), ty: Ty::Primitive('u16') },
Member { name: 'z', attrs: ['four'].span(), ty: Ty::Primitive('u32') }
].span();
upgraded
.children =
[
Member { name: 'x', attrs: ['two'].span(), ty: Ty::Primitive('u8') },
Member { name: 'y', attrs: ['three'].span(), ty: Ty::Primitive('u16') },
Member { name: 'z', attrs: ['four'].span(), ty: Ty::Primitive('u32') },
]
.span();
assert!(upgraded.is_an_upgrade_of(@s), "new member");
}

#[test]
fn test_enum_upgrade() {
let e = Enum {
name: 'e', attrs: [
'one'
].span(), children: [
('x', Ty::Primitive('u8')), ('y', Ty::Primitive('u16')),
].span()
name: 'e',
attrs: ['one'].span(),
children: [('x', Ty::Primitive('u8')), ('y', Ty::Primitive('u16'))].span(),
};

// different name
Expand All @@ -438,33 +518,43 @@ fn test_enum_upgrade() {

// variant name changed
let mut upgraded = e;
upgraded.children = [('new', Ty::Primitive('u8')), ('y', Ty::Primitive('u16')),].span();
upgraded.children = [('new', Ty::Primitive('u8')), ('y', Ty::Primitive('u16'))].span();
assert!(upgraded.is_an_upgrade_of(@e), "variant name changed");

// allowed variant change
let mut upgraded = e;
upgraded.children = [('x', Ty::Primitive('u16')), ('y', Ty::Primitive('u16'))].span();
assert!(upgraded.is_an_upgrade_of(@e), "allowed variant change");

// wrong variant change
let mut upgraded = e;
upgraded.children = [('x', Ty::Primitive('u8')), ('y', Ty::Primitive('u8')),].span();
upgraded.children = [('x', Ty::Primitive('u8')), ('y', Ty::Primitive('u8'))].span();
assert!(!upgraded.is_an_upgrade_of(@e), "wrong variant change");

// new member
let mut upgraded = e;
upgraded.children = [
('x', Ty::Primitive('u8')), ('y', Ty::Primitive('u16')), ('z', Ty::Primitive('u32'))
].span();
upgraded
.children =
[('x', Ty::Primitive('u8')), ('y', Ty::Primitive('u16')), ('z', Ty::Primitive('u32'))]
.span();
assert!(upgraded.is_an_upgrade_of(@e), "new member");
}

#[test]
fn test_tuple_upgrade() {
let t = Ty::Tuple([Ty::Primitive('u8'), Ty::Primitive('u16')].span());

// tuple item is upgradable
let upgraded = Ty::Tuple([Ty::Primitive('u16'), Ty::Primitive('u16')].span());
assert!(upgraded.is_an_upgrade_of(@t));

// tuple item is not upgradable
let upgraded = Ty::Tuple([Ty::Primitive('bool'), Ty::Primitive('u16')].span());
assert!(!upgraded.is_an_upgrade_of(@t));

// tuple length changed
let upgraded = Ty::Tuple(
[Ty::Primitive('u8'), Ty::Primitive('u16'), Ty::Primitive('u32')].span()
[Ty::Primitive('u8'), Ty::Primitive('u16'), Ty::Primitive('u32')].span(),
);
assert!(!upgraded.is_an_upgrade_of(@t));
}
Expand All @@ -473,6 +563,10 @@ fn test_tuple_upgrade() {
fn test_array_upgrade() {
let a = Ty::Array([Ty::Primitive('u8')].span());

// array item is upgradable
let upgraded = Ty::Array([Ty::Primitive('u16')].span());
assert!(upgraded.is_an_upgrade_of(@a));

// array item is not upgradable
let upgraded = Ty::Array([Ty::Primitive('bool')].span());
assert!(!upgraded.is_an_upgrade_of(@a));
Expand Down
76 changes: 61 additions & 15 deletions crates/dojo/core/src/meta/introspect.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -39,35 +39,81 @@ pub trait TyCompareTrait<T> {
fn is_an_upgrade_of(self: @T, old: @T) -> bool;
}

impl PrimitiveCompareImpl of TyCompareTrait<felt252> {
fn is_an_upgrade_of(self: @felt252, old: @felt252) -> bool {
if self == old {
return true;
}

let mut allowed_upgrades: Span<(felt252, Span<felt252>)> = [
('bool', [].span()), ('u8', ['u16', 'u32', 'usize', 'u64', 'u128', 'felt252'].span()),
('u16', ['u32', 'usize', 'u64', 'u128', 'felt252'].span()),
('u32', ['usize', 'u64', 'u128', 'felt252'].span()),
('usize', ['u32', 'u64', 'u128', 'felt252'].span()),
('u64', ['u128', 'felt252'].span()), ('u128', ['felt252'].span()), ('u256', [].span()),
('i8', ['i16', 'i32', 'i64', 'i128', 'felt252'].span()),
('i16', ['i32', 'i64', 'i128', 'felt252'].span()),
('i32', ['i64', 'i128', 'felt252'].span()), ('i64', ['i128', 'felt252'].span()),
('i128', ['felt252'].span()), ('felt252', ['ClassHash', 'ContractAddress'].span()),
('ClassHash', ['felt252', 'ContractAddress'].span()),
('ContractAddress', ['felt252', 'ClassHash'].span()),
]
.span();

loop {
match allowed_upgrades.pop_front() {
Option::Some((
src, allowed,
)) => {
if src == old {
let mut i = 0;
break loop {
if i >= (*allowed).len() {
break false;
}
if (*allowed).at(i) == self {
break true;
}
i += 1;
};
}
},
Option::None => { break false; },
}
}
}
}

impl TyCompareImpl of TyCompareTrait<Ty> {
fn is_an_upgrade_of(self: @Ty, old: @Ty) -> bool {
match (self, old) {
(Ty::Primitive(n), Ty::Primitive(o)) => n == o,
(Ty::Primitive(n), Ty::Primitive(o)) => n.is_an_upgrade_of(o),
(Ty::Struct(n), Ty::Struct(o)) => n.is_an_upgrade_of(o),
(Ty::Array(n), Ty::Array(o)) => { (*n).at(0).is_an_upgrade_of((*o).at(0)) },
(
Ty::Tuple(n), Ty::Tuple(o)
Ty::Tuple(n), Ty::Tuple(o),
) => {
let n = *n;
let o = *o;
if n.len() == o.len() {
let mut i = 0;
loop {
if i >= n.len() {
break true;
}
if !n.at(i).is_an_upgrade_of(o.at(i)) {
break false;
}
i += 1;

if n.len() != o.len() {
return false;
}

let mut i = 0;
loop {
if i >= n.len() {
break true;
}
if !n.at(i).is_an_upgrade_of(o.at(i)) {
break false;
}
} else {
false
i += 1;
}
},
(Ty::ByteArray, Ty::ByteArray) => true,
(Ty::Enum(n), Ty::Enum(o)) => n.is_an_upgrade_of(o),
_ => false
_ => false,
}
}
}
Expand Down

0 comments on commit 0d63941

Please sign in to comment.