Transaction hash white listing

We have some discussion at Flow discord about Transaction hash whitelisting and I posted the high-level thinking here and would welcome comments.
1: for state change functions in a Contract, especially regarding resource move functions, we need to validate the transaction hash.

2: For all other functions such as read state or trivial state change we do not need to validate script or transaction hash.

3: the hash can be generated and validated in a trustless way or decentralized way.

4: the whitelist for transaction hash is stored in a Registry within a contract or within an account.

5: There is a validation of the transaction hash at the Flow protocol layer (this is the best place if doable and if we can do it, this would be very innovative blockchain in the world) or at Contract or Function layer down the calling stack.

6: the Wallet can be leveraged for transaction validation as well but it is not an optimal option:-).

In summary, If Flow Blockchain could validate the caller’s transaction code hash (not parameters) or caller’s Contract hash before executing a function if that function has @checkhash modifier. If we can do this, and give this as an optional modifier to enable the developer to use it, the whole flow ecosystem will be very secure. The developer will still have the freedom and the option to choose which function to enable the hash check. If you are developing a protocol-level application, you may not want to use this whitelist pattern. But for matured Dapp which is not used by other Dapps, this is one of the best defense measures to protect your Dapp.

Based on the following Discord conversion, I believe a token-based approach is better. Thanks, @bluesign for the discussion and design pattern.

[7:35 AM] bluesign*:*

problem there is what is malicious transaction, if you have FungibleToken contract, is it ok if you whitelist withdraw?

[7:37 AM] bluesign*:*

technically your public function is what you whitelisted for use.

[8:53 AM] nduplessis*:*

Agreed, the action needs context

[8:54 AM] nduplessis*:*

When is withdraw safe vs unexpected

@bluesign

problem there is what is malicious transaction, if you have FungibleToken contract, is it ok if you whitelist withdraw?

[8:54 AM] kenhuangus*:*

Malicious transactions are the transactions which explorer a security flaw in your contract and with draw funds. For the FungibleToken, it is a protocol level primitives, you certainly do not want to white list the public functions. The case for white list is for a standalone Dapp which sits on the top of other DeFi or NFT primitives, but no other Dapp will be built on top of it. So, the public function in the Contract inside this Dapp will only be used by this Dapp’s transactions or contract within this DAPP only.

@kenhuangus

Malicious transactions are the transactions which explorer a security flaw in your contract and with draw funds. For the FungibleToken, it is a protocol level primitives, you certainly do not want to white list the public functions. The case for white list is for a standalone Dapp which sits on the top of other DeFi or NFT primitives, but no other Dapp will be built on top of it. So, the public function in the Contract inside this Dapp will only be used by this Dapp’s transactions or contract within this DAPP only.

[8:55 AM] bluesign*:*

But don’t you limit this by exposing a signature. MyFunction takes those parameters, returns this.

[8:56 AM] bluesign*:*

Why you will need to whitelist that part?

[8:56 AM] kenhuangus*:*

So, essentially we need to distinguish two types of Dapps. One is the Dapp which is financial primitives, the pub function shall not have any white list in this case. Another one is stand alone Dapp

[8:56 AM] kenhuangus*:*

white list the caller of the function.

[8:57 AM] bluesign*:*

@kenhuangus can you give one example? It is hard to discuss on theory, like kitty items for example, should whitelist what?

[9:00 AM] kenhuangus*:*

for example whitelist the caller of pub fun removeSaleOffer(saleOfferResourceID: UInt64)

@kenhuangus

for example whitelist the caller of pub fun removeSaleOffer(saleOfferResourceID: UInt64)

[9:02 AM] bluesign*:*

to a transaction hash ? like hash of this: https://github.com/onflow/kitty-items/blob/898c1c3178453d83b9f2fe390d34ff347d147277/cadence/transactions/nftStorefront/remove_item.cdc(edited)

[9:03 AM] kenhuangus*:*

Yes, but this is off chain verification. Correct?

[9:04 AM] bluesign*:*

I mean on-chain solution will use some transaction hash. (caller is transaction)(edited)

[9:04 AM] kenhuangus*:*

Yes, this is what I would like to see happening and could be good for the ecosystem

[9:05 AM] bluesign*:*

So if I am using kitty-items, then I have listed 100 sale offers, you are forcing me to remove them 1 by 1 ?

[9:06 AM] kenhuangus*:*

no. the actual parameter value should not be included in the hash.

[9:06 AM] kenhuangus*:*

only the transaction code hash is calculated and validate on chain or somewhat decentalized fashin

[9:06 AM] bluesign*:*

yeah but I am coming from transaction, so it is kind of allow calls from transaction ?

[9:07 AM] bluesign*:*

cause now I have remove_item.cdc, if I hash this, without parameter, it is still removing one by one

[9:07 AM] kenhuangus*:*

Yes, white list the allowed transactions to my contract pub function in a decentalized way

[9:08 AM] bluesign*:*

now I cannot write something like :

 for saleOffer in getMySaleOffers(): removeSaleOffer(saleOffer.id)

[9:08 AM] kenhuangus*:*

You can have another function to removeAll

[9:09 AM] bluesign*:*

yeah the problem is , then you need to cover all possible cases, in advance

[9:09 AM] kenhuangus*:*

white listing the caller should not impede the contract developer to develop pub function. it is just provide a tool

[9:09 AM] bluesign*:*

actually then you don’t even need transactions, basically you have functions on contract

@kenhuangus

white listing the caller should not impede the contract developer to develop pub function. it is just provide a tool

[9:11 AM] bluesign*:*

Yeah the problem is people tend to abuse more than use

@bluesign

now I cannot write something like : for saleOffer in getMySaleOffers(): removeSaleOffer(saleOffer.id)

[9:12 AM] kenhuangus*:*

For this use case, your transaction code can do the loop and add the code hash to the whitelist, you actually do not need to implement removeAll fucntion.

@kenhuangus

For this use case, your transaction code can do the loop and add the code hash to the whitelist, you actually do not need to implement removeAll fucntion.

[9:13 AM] bluesign*:*

yeah but you are the contract, I am the user. You need to whitelist me for this. As I said when you used like this, it is better to expose something like ‘stored procedure’ to users, in the end you say only allowed transactions can use my contract function.(edited)

[9:15 AM] bluesign*:*

Actually my point is: if you have some usage limit in your mind, why not expose this limit as a function ? ( I mean the transaction as a function ) instead of whitelisting transaction

[9:16 AM] kenhuangus*:*

Again, I believe that my point of view is from stand alone Dapp perspective what I have limited transactions to implement for my pub function and I do not want to other project to call into my pub function. And your point (which is also valid ) is from building financial primitives so everyone can use it. Both are ok. But on chain white listing hash verification shall be a good tool and a plus. Correct?

[9:16 AM] bluesign*:*

but another dapp can run your transaction ? if you can somehow blacklist dapp to run your transaction maybe can be good, but if I can run your transaction for me there is no added benefit there. But I think you can manage that currently with cadence crypto already.(edited)

@bluesign

Actually my point is: if you have some usage limit in your mind, why not expose this limit as a function ? ( I mean the transaction as a function ) instead of whitelisting transaction

[9:19 AM] kenhuangus*:*

This is good point and I guess that we need the balance of writing transaction as function vs. a function allow limited use by (internal defined) transactions.

[9:20 AM] bluesign*:*

I think what you want in my opinion is verified calling of a function.

[9:20 AM] kenhuangus*:*

right

[9:22 AM] bluesign*:*

I think some token solution can be better, problem is at whitelist.(edited)

[9:23 AM] kenhuangus*:*

I am intrigued by the token solution. please elaborate?

[9:23 AM] bluesign*:*

it is a bit of off-chain permission to take some action on on-chain.

[9:24 AM] bluesign*:*

so you have a function X with parameters a,b,c :

fun X (a,b,c) 

[9:24 AM] bluesign*:*

then you add some token to this function :

[9:24 AM] bluesign*:*

fun X (a,b,c,token)

[9:24 AM] bluesign*:*

here you

token = sign(hash(X . a . b. c ))

[9:25 AM] bluesign*:*

and when you are in X you verify if token signature is valid

[9:27 AM] bluesign*:*

so you can allow/deny off-chain usage of the contract

[9:28 AM] bluesign*:*

I oversimplified though

[9:28 AM] bluesign*:*

but gist of it is like this

[9:28 AM] kenhuangus*:*

yes, I see your point. the token here is a kind of like oAuth token with contract owner’s signature. This is a good design.

[9:30 AM] bluesign*:*

Yeah you can have multi calls in a single token also

[9:30 AM] bluesign*:*

like oauth scopes

[9:31 AM] bluesign*:*

I did implement one time scopes like this on a contract for fun, it is pretty powerful

[9:31 AM] kenhuangus*:*

make sense. It is an excellent security usage pattern for critical pub functions in Cadence contract. I will add this to the checklist and the developer can use this as an optional tool to protect the code.

Please define “trvial state change”.

In my opinion, “trivial state change” means the state change which does not have a financial impact on the blockchain ecosystem.