#Top Authorizations
51 messages · Page 1 of 1 (latest)
usability and usefulness: it's much easier to specify the flat list on one hand and most of the time the inner authorizations are not relevant. the tree version should be there as well, but I never really had time for it.
e.g. if a contract calls token transfer you, of course could verify that the token authorization has been called, but that would just cover SAC code in your test
I'm less interested in a tree. The flat list is easier, but afaict if I'm trying to test that a require_auth occurs in a subcontract call, my test has to assert that the auth happened in the root call, which is confusing.
yeah, we definitely need a tree version
We could have a flat list of all require_auth's, so instead of including the root, it'd be the subcontract call in the list.
If both the root and subcontract call require_auth, then both can be in the list.
(topologically; the format can be whatever is convenient)
flattening tree to a list would be somewhat inconvenient as every vertex has to be duplicated. but maybe that's better than recursive structure - not really sure here...
i.e. list would be [A, A->B, A->B->C], while tree is just A->B->C
For a call tree A->B->C where A and C call require_auth, I think the list can be: [A, C]
But yeah, exposing the full call tree would provide that info too.
sure; what I mean is that if the factual tree is A->B->C ,then with the list-based approach you need to specify the whole tree path for every item, which is a bit verbose
Actually, I'm getting confused, I see a comment saying that the "top authorization" is the first to have called require_auth.
yes, that's the tree root
So AuthorizationTrackers root invocation is always the first in a call tree who called require_auth? Even in enforced auth?
the name kind of sucks
yes, that's intentional
and allows batching operations or doing routing
So if I specify ContractAuth call tree of A->B->C, and only C calls require_auth, then the AuthorizationTracker for that call tree will have a root invocation of C?
yes
I've tried to describe this in a more formal fashion here: https://soroban.stellar.org/docs/learn/authorization#matching-authorized-invocation-trees
Hmm, but I see this, where the root invocation of the AuthorizationTracker is the root invocation of the ContractAuth, in the example above A, not C:
https://github.com/stellar/rs-soroban-env/blob/main/soroban-env-host/src/auth.rs#L556
right, but the mapping from the tree to the actual call stack is performed by the auth manager
'root' in ContractAuth tree refers to the root of the tree you're authorizing on your behalf. it doesn't need to match to the root of the contract invocation
Ok got it. So the top level authorization could be a contract that didn't call require_auth, if a developer included calls higher in the call tree than they needed. Is that accurate?
In recording mode it will always be the first point where require_auth is called, but when used on a network, someone could pass a ContractAuth containing a root that never needed auth and that never called require_auth. And in our definition of the top-level authorization, it would be the ContractAuth root?
doesn't seem so, but I might misunderstand this. the top authorization matches the 'first' require_auth call(s) in the tree (i.e .roots of the 'condensed' trees in the forest, as per doc above)
someone could pass a ContractAuth containing a root that never needed auth
this would not be matches to the invocations and hence the transaction will fail
. And in our definition of the top-level authorization, it would be the ContractAuth root?
yes, these are roots of theContractAuthentries, which might or might not coincide with the top-level call
I know this is hard to digest; I guess that's the cost of flexibility. I hope 95+% of the time only the simple trees are needed and there is no need to understand all the intricacies...
I don't think I understand this yet, but I'll try writing a few tests to see if I can piece together from the behavior I see what the invariants and principles are.
I think auth is an area we need to find a way for every intricacy to be easily understood.
I have to say auth does feel like a moving target!
We appreciate your patience and perseverance!
🍻 don't mention it, I know how hard you guys are working on this!!! Sure hope to see everything fly high @ Meridian! 🙂
BTW, not entirely relevant, but since "declarative" was used at some point to explain auth, I always wondered why we didn't use decorators for fn, like #[private] and #[payable] to restrict the invokercaller? (like NEAR)
this has been a consideration, but rust doesn't really have decorators
something might be doable with macros though...
decorator used here as the pattern, they are implemented as macros in near 🙂
You can have private functions, just drop the pub, and other contracts won't be able to call them.
private here means only callable by the account that deployed the contract, doesnt have to do with visibility of the fn 🙂
yeah, sure. I didn't succeed at trying to do 'decorator' style macro attributes inside contractimpl, but I'm not proficient enough at proc macros though
but it definitely cause at least some friction due to macro nesting
We could add decorators for require_auth on addresses I guess, but I think what we've landed on is already as simple, and the decorator raises more questions as a reader.
https://github.com/stellar/rs-soroban-env/issues/660 is 3 months old and really I always wanted to have something, but never really had time for a prototype
like macro could auto-generate an address argument... but at that point it seems to be more confusing than readable
thank you both for answering! I just had that question on the back of my mind for way too long 🙂
660 clearly makes a strong case for "if no one is asking why bother" 😆 I just find it interesting that there were no requests for something like fn decor (macros) to "simplify" auth from an external party(ies) aka community.
well, there were a few threads regarding the 'invoker' (not in a decorator context, just in general)... but really I'm not sure if introducing it artificially would make things simpler. also for the simple cases it's 1 line of code (decorator) vs 1 line of code (require_auth)
that's true, I mean at this point this is just opinion, but I do feel that quickly glancing at a decorator on top of a fn decl to explicitly declare the security policy applied to it is a bit more... hmm convenient? than having to read through the fn's code ... again, just my opinion no need to dwell on this topic any longer