Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set function access in Json ABI based on presence of ctx and self parameter #783

Merged
merged 10 commits into from
Dec 3, 2022
27 changes: 23 additions & 4 deletions crates/abi/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ impl AbiFunction {
name: String,
args: Vec<(String, AbiType)>,
ret_ty: Option<AbiType>,
has_self: bool,
has_ctx: bool,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to take simply state_mutability instead of introducing Fe-specific concepts like self and ctx to avoid unnecessary tight coupling with Fe language specification.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mut would be launched soon. So I think it'd be better to finish the PR after its deployment.

Okay. I got it!

) -> Self {
let inputs = args
.into_iter()
Expand All @@ -48,7 +50,12 @@ impl AbiFunction {
// In the future we will derive that based on the fact whether `self` or `ctx` are taken as `mut` or not.
// For now, we default to payable so that tooling such as hardhat simply assumes all functions need to be
// called with a transaction.
state_mutability: StateMutability::Payable,
// And if self and ctx are note taken then we use `pure` as state mutability
state_mutability: if !has_self && !has_ctx {
StateMutability::Pure
} else {
StateMutability::Payable
},
}
}

Expand Down Expand Up @@ -131,7 +138,8 @@ mod tests {

AbiType::Tuple(vec![field1, field2])
}
fn test_func() -> AbiFunction {

fn test_func(has_self: bool, has_ctx: bool) -> AbiFunction {
let i32_ty = AbiType::Int(32);
let tuple_ty = simple_tuple();
let u64_ty = AbiType::UInt(64);
Expand All @@ -141,12 +149,14 @@ mod tests {
"test_func".into(),
vec![("arg1".into(), i32_ty), ("arg2".into(), tuple_ty)],
Some(u64_ty),
has_self,
has_ctx,
)
}

#[test]
fn serialize_func() {
let func = test_func();
let func = test_func(true, true);

assert_ser_tokens(
&func,
Expand Down Expand Up @@ -211,9 +221,18 @@ mod tests {
)
}

#[test]
fn test_state_mutability() {
let pure_func = test_func(false, false);
assert_eq!(pure_func.state_mutability, StateMutability::Pure);

let impure_func = test_func(true, false);
assert_eq!(impure_func.state_mutability, StateMutability::Payable);
}

#[test]
fn func_selector() {
let func = test_func();
let func = test_func(true, true);
let selector = func.selector();

debug_assert_eq!(
Expand Down
9 changes: 9 additions & 0 deletions crates/analyzer/src/namespace/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,10 @@ impl FunctionSigId {
self.signature(db).self_decl.is_some()
}

pub fn takes_ctx(&self, db: &dyn AnalyzerDb) -> bool {
self.signature(db).ctx_decl.is_some()
}

pub fn self_type(&self, db: &dyn AnalyzerDb) -> Option<types::TypeId> {
match self.parent(db) {
Item::Type(TypeDef::Contract(cid)) => Some(types::Type::SelfContract(cid).id(db)),
Expand Down Expand Up @@ -1274,6 +1278,11 @@ impl FunctionId {
pub fn takes_self(&self, db: &dyn AnalyzerDb) -> bool {
self.sig(db).takes_self(db)
}

pub fn takes_ctx(&self, db: &dyn AnalyzerDb) -> bool {
self.sig(db).takes_ctx(db)
}

pub fn self_span(&self, db: &dyn AnalyzerDb) -> Option<Span> {
self.sig(db).self_span(db)
}
Expand Down
9 changes: 8 additions & 1 deletion crates/codegen/src/db/queries/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,14 @@ pub fn abi_function(db: &dyn CodegenDb, function: FunctionId) -> AbiFunction {
AbiFunctionType::Function
};

AbiFunction::new(func_type, name.to_string(), args, ret_ty)
AbiFunction::new(
func_type,
name.to_string(),
args,
ret_ty,
sig.has_self,
sig.has_ctx,
)
}

pub fn abi_function_argument_maximum_size(db: &dyn CodegenDb, function: FunctionId) -> usize {
Expand Down
12 changes: 10 additions & 2 deletions crates/codegen/src/yul/runtime/revert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,16 @@ fn type_signature_for_revert(db: &dyn CodegenDb, name: &str, ty: TypeId) -> yul:
}
};

let selector =
AbiFunction::new(AbiFunctionType::Function, name.to_string(), args, None).selector();
// selector and state mutability is independent we can set has_self and has_ctx any value.
let selector = AbiFunction::new(
AbiFunctionType::Function,
name.to_string(),
args,
None,
true,
true,
)
.selector();
let type_sig = selector.hex();
literal_expression! {(format!{"0x{}", type_sig })}
}
1 change: 1 addition & 0 deletions crates/mir/src/ir/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub struct FunctionSignature {
pub analyzer_func_id: analyzer_items::FunctionId,
pub linkage: Linkage,
pub has_self: bool,
pub has_ctx: bool,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Expand Down
2 changes: 2 additions & 0 deletions crates/mir/src/lower/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub fn lower_monomorphized_func_signature(
// TODO: Remove this when an analyzer's function signature contains `self` type.
let mut params = vec![];
let has_self = func.takes_self(db.upcast());
let has_ctx = func.takes_ctx(db.upcast());

if has_self {
let self_ty = func.self_type(db.upcast()).unwrap();
Expand Down Expand Up @@ -89,6 +90,7 @@ pub fn lower_monomorphized_func_signature(
analyzer_func_id: func,
linkage,
has_self,
has_ctx,
};

db.mir_intern_function(sig.into())
Expand Down