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

Pure Proxy Replication #111

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

muharem
Copy link
Contributor

@muharem muharem commented Aug 12, 2024

from ## Summary

This RFC proposes a solution to replicate an existing pure proxy from one chain to others. The aim is to address the current limitations where pure proxy accounts, which are keyless, cannot have their proxy relationships recreated on different chains. This leads to issues where funds or permissions transferred to the same keyless account address on chains other than its origin chain become inaccessible.

Copy link
Contributor

@xlc xlc left a comment

Choose a reason for hiding this comment

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

There is another drawback which is unlikely but nevertheless needs to be considered.
Say we have 3 parachains, A, B, and C
3 accounts, Alice, Bob, Charlie
Alice created a pure proxy on chain A: Alice#1@A
Alice created a pure proxy on chain B with the exact same parameters: Alice#1@B
The preimage data (and therefore the hash) for Alice#1@A and Alice#1@B are exactly the same
The ownership of Alice#1@A is transferred to Bob (e.g. the account had some staked asset and Alice sold them to Bob by transferring the pure proxy ownership)
The ownership of Alice#1@B is transferred to Charlie
Now some assets are airdropped to Alice#1@C
Both Bob and Charlie want to replicate the proxy on chain C to gain control of the airdropped asset.
What now?

This issue exists because there is no chain specific data in the pure proxy preimage (e.g. chain genesis). The proper fix is to introduce such data to the preimage but it wouldn't fix the legacy issue.
I don't know what will be the solution and I don't even sure if it is possible to have a solution, unfortunately.

That's one of the reason why ss58 prefix is important because it distinguishes the accounts between chains. Similar issue exists on other EVM chains. There were multiple attacks caused by people are able to take control of gnosis safe ownership by replicate the contract deployment using a same nonce and the original owner were expecting they control such contract on other EVM networks, which is not always true.

- The receiving chain has to trust the sending chain's claim that the account controlling the pure account has commanded the replication.
- Clients must obtain witness data.

We could eliminate the first disadvantage by allowing only the spawner of the pure proxy to recreate the pure proxies, if they sign the transaction on a remote chain and supply the witness/preimage. Since the preimage of a pure account includes the account ID of the spawner, we can verify that the account signing the transaction is indeed the spawner of the given pure account. However, this approach would grant exclusive rights to the spawner over the pure account, which is not a property of pure proxies at present. This is why it's not an option for us.
Copy link
Contributor

Choose a reason for hiding this comment

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

yeah we shouldn't do this. it is for example the spawner private key is forgotten because people wasn't expecting they need it anymore

@muharem
Copy link
Contributor Author

muharem commented Aug 14, 2024

@xlc good point, thank you. what if we a receiving chain will require no proxy records for a replicated pure account?

@xlc
Copy link
Contributor

xlc commented Aug 14, 2024

It is not going to help (if not make the problem worse). Both Bob and Charlie can still try to claim Alice#1@C and it will just be whomever is the fastest. And without the witness data, root origin on chain A or B can even try to claim non pure proxy account.

I guess it could just let it be a known issue without solution and we just accept it and life continues. Not every bug requires fix but at least we are making a considered decision.

@muharem
Copy link
Contributor Author

muharem commented Aug 14, 2024

@xlc makes sense. we should allow multiple replications of the same pure account with different proxy accounts. I think we can allow clients of the pallets to add an additional custom seed into the pure account preimage.

@xlc
Copy link
Contributor

xlc commented Aug 14, 2024

I think we can allow clients of the pallets to add an additional custom seed into the pure account preimage.

Yes that will improve the security.

@muharem
Copy link
Contributor Author

muharem commented Aug 15, 2024

@xlc I have included your note. thank you


### Ergonomics

The proposed solution does not alter any existing interfaces. It does require clients to obtain the witness data which should not be an issue with support of an indexer.
Copy link
Contributor

Choose a reason for hiding this comment

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

Clients would need to get this witness data and perform the replication before any action on another chain. When would they know to do the replication?

Copy link
Contributor

Choose a reason for hiding this comment

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

when they want to use the proxy account on dest chain. i.e. requires user to manually initiate the replication

text/0111-pure-proxy-replication.md Outdated Show resolved Hide resolved
text/0111-pure-proxy-replication.md Outdated Show resolved Hide resolved
@AndreiEres
Copy link

I think we can allow clients of the pallets to add an additional custom seed into the pure account preimage.

Is it correct that it's no longer keyless then?

I'm curious about how ownership of a pure account is defined and how it can be transferred. As far as I know, the deposit for the pure account remains with its creator indefinitely.

I assume that the creator of pure accounts could simply be an operational account used for initialization. For example, if it creates three pure accounts to form a multisig, it could then connect those pure accounts to other users and remove its own link. In that scenario, the new owner's identity is clear. However, it’s also possible for one pure account to be connected to different types of proxies. In that case, who would be considered the owner?

It's obvious but important to note that there is a security risk if the creator were to restore its link to the pure account on another chain, after having removed it from the original one.

@xlc
Copy link
Contributor

xlc commented Sep 3, 2024

Is it correct that it's no longer keyless then?

The seed is not private key seed, but hash preimage payload (it shouldn't be called seed).

As far as I know, the deposit for the pure account remains with its creator indefinitely.

The deposit issue is unrelated but nevertheless a bug should be fixed (paritytech/polkadot-sdk#237, paritytech/substrate#8550)

who would be considered the owner

There is no concept of owner.

there is a security risk if the creator were to restore its link to the pure account on another chain

This is never this RFC about and obviously should never happen unless the proxy account explicitly wants it.

@AndreiEres
Copy link

The seed is not private key seed, but hash preimage payload (it shouldn't be called seed).

Sorry for misleading it was mostly a joke :-)

There is no concept of owner.

You wrote

The ownership of Alice#1@A is transferred to Bob

That's my question about.

@xlc
Copy link
Contributor

xlc commented Sep 4, 2024

The onchain pallet doesn't have concept of owner. A pure proxy can be controlled by no one (which shouldn't happen but the last owner can remove itself) or multiple. And then we have proxy type so some accounts could have limited control, for example, A have TransferOnly and B have EverythingButTransfer. So yeah we should avoid owner in RFC.

What is actually happening is some accounts have the authorization to request the pure proxy to do kind of action (the kind is determined by the proxy type). That's it.

@AndreiEres what is your question again?

@AndreiEres
Copy link

@AndreiEres what is your question again?

I think I'm good, thank you. I had some edge cases in my head but the goal of the RFC is more broad and there are more important security questions.

@anaelleltd anaelleltd added the Proposed Is awaiting 3 formal reviews. label Sep 16, 2024
@joepetrowski
Copy link
Contributor

Is there anything to address here or can we get it to a vote? @muharem

@bkchr
Copy link
Contributor

bkchr commented Sep 28, 2024

While I'm very late to the party, sorry. I would have a different proposal, but do with it whatever you want ;)

Instead of replicating the proxies everywhere, I would propose we put them on one or two chains only. From there we can do proofs that the pure proxy exists on the destination chain. I would assume that proxies only exists on the people or maybe only on AH. When you want to call something on parachain X using your proxy, you would forward a proof of the data inside the state of AH/People chain to parachain X. Each parachain tracks the relay chain storage root and based on this we can get the individual heads of each parachain and with this we can check the storage proof from the proxy holding chain. This way we don't need to have the proxy everywhere and also all parachains probably trust the system chains.

@xlc
Copy link
Contributor

xlc commented Sep 29, 2024

Yeah we don't really need a native replicate function. What we need is authenticate that allow the source chain to dispatch some transact on dest chain for some proxy account.

The transact can be addProxy to perform the replication if needed.

So for one time usage, people can just use transact to do whatever they want. But if they want to do something on the dest chain repetitively, they can replicate the proxy to avoid the XCM overhead.

@bkchr
Copy link
Contributor

bkchr commented Sep 30, 2024

What I proposed doesn't use XCM at all and just uses proofs to prove the existence of the proxy.

@xlc
Copy link
Contributor

xlc commented Sep 30, 2024

One key difference will be how much of internal details that we would like to be spec'ed and fixed?
For the XCM case, that will be how the pure proxy account is derived.
For the storage proof case, that will be the storage layout details.
I personally prefer XCM here because it is more flexible/forward compatible.
We already know how much of headaches to depending on the pallet storage layout and trying to come up solutions to avoid that (XCQ or view functions) so I don't want to add another case to expose and pin the storage layout.

@burdges
Copy link

burdges commented Sep 30, 2024

On-chain messaging should've base costs like 30 x more than off-chain messaging, but congestion should hopefully make them cost much more. Any off-chain message requires a state proof, so on-chain messaging should not remain more flexible/forward compatible, but this requires nice storage abstraction traits (not even planned for JAM yet).

I think proofs have very different semantics from replication, with replication closely resembling airdrops, so definitely a popular usecase, but not universal.

Internally though, we'll need proofs to split polkadot functionality into multiple parachains: A governance vote needs the current locks state, not airdrops of past state, as well as proofs into the vote for early unlocking. An on-chain messaging protocol cannot handle this many messages btw.

App parachains who outgrow elastic scaling might employ off-chain messages with guaranteed delievery for account migration between their parachain shards, but their governance might resemble this polkadot model.

As an aside, validator ellections could be done by a temporary "fork" of whatever chain holds the nominators accounts, aka one huge off-chain message, so neither a proof nor an airdrop/replication.

@muharem
Copy link
Contributor Author

muharem commented Oct 2, 2024

Please correct me if I am wrong, the solution with the off-chain proof submission would look like:

The client/wallet on a user request pulls the proxy ownership proof (1) (the whole sub trie) from the chain that sources the proxies, block height (2) at which the poof was pulled and constructs keyless/pure account witness (3) (as in the present RFC, currently proxy pallet does not differentiate a keyless/pure accounts and general accounts or we open it for all proxies). With these arguments now the client constructs the target call for a user. The user must submit this call from the account that has an ownership of the proxy. This composite call contains the arguments (1), (2) and (3).

Concerns:

  • how big can be the proof (1)? it will take the capacity of PoV and extrinsic length within the block.
  • in case of a multisig owning the pure proxy, it might take time for to dispatch the call with proof, how old can be the proof/height?

The client submits the extrinsic to a target chain. The target chain's runtime has to know the part of the source chain's storage layout (the part concerning the proof) and be able to obtain the source chain's state root at a give height (2). The target chain verifies that the height is not too old, verifies the proof (1) and the witness (3) data. If all valid the target chain proxies the call.

Where am I wrong or missing something? @bkchr @xlc

A governance vote needs the current locks state, not airdrops of past state, as well as proofs into the vote for early unlocking. An on-chain messaging protocol cannot handle this many messages btw.

@burdges
Correct me if I misunderstood you. I think we wont need a cross chain message for every vote for example. With on0chain messaging we can create a remote lock once (create a lock on source chain, it's representation on remote chain and delegate the ownership of it for a given origin) and reuse it for many votes. We need a on-chain message if we wanna extend/release lock. Same with pure proxies, a user needs to replicate it once with on-chain message.

@bkchr
Copy link
Contributor

bkchr commented Oct 2, 2024

how big can be the proof (1)? it will take the capacity of PoV and extrinsic length within the block.

Depends on the trie depth ;) If you would replicate the proxies on the destination chain, loading the proxy from the destination state versus delivering the proof alongside the call should not make such a big difference.

in case of a multisig owning the pure proxy, it might take time for to dispatch the call with proof, how old can be the proof/height?

This is a good point. In the end it depends on how long we want to store the storage roots of the proxy providing chain. However, we could come up with a solution that uses the dispatch local context to store the proof, then the final multisig tx could provide this information.

@acatangiu
Copy link
Contributor

IIUC:

  1. original (onchain XCM) proposal:
  • any account in this situation can replicate the proxy relationship on a remote chain - one time action - not bad
  • freely use the "new" proxy on the other chain - nice
  • I gather from Basti's reply that this "sticky" replication on the remote chain is somehow a disadvantage? why?
  1. offchain proofs alternative
  • original proxy is on AH or People or both or also on some other chain
  • using the "equivalent proxy" on another chain requires proving the validity of the proxy - every time - poorer UX, more expensive

The implementation+deployment complexities of the two options are comparable, but 2nd option would have higher maintenance cost because of its dependency on storage layouts, and IMO poorer UX. So unless I am missing something, I am supporting the onchain XCM path.

@burdges
Copy link

burdges commented Oct 3, 2024

how big can be the proof (1)? it will take the capacity of PoV and extrinsic length within the block.

It's completely irrelevant in the worst case..

Polkadot only validates stateless blocks, so a collators expands the block by every Merkle proof required for the state proofs, so in the worst case all transactions have size tx+size + field_accesses * 32 * log state_size.

If a user submits proof into chan A in transaction on chain B, then the user's proof has size 32 * log_2 state_size_of_chain_a, but field_accesses decreases by one, so in the worst case nothing changes if chain A and chain B have the same state size.

In fact, we do not work in the worse case because collators merge those Merkle proofs, which saves considerable space. Interestingly, we achieve this merger by running a generic compression algorithm, which while less efficent than simply merging them manually, does ensure that if you many transactions have Merkle proofs into a specific chain, then those merge too.

All told, I'd expect Merkle proofs into other parachains const little in practice, not because they do not take space, but because you'd pay that space anyways, assuming all users behave somewhat similarly. You can save space by minimizing state accesses though.

in case of a multisig owning the pure proxy, it might take time for to dispatch the call with proof, how old can be the proof/height?

An on-chain multi-sig was never a great idea. We only do them because we're a blockchain company and so we first think about doing things on-chain.

A cryptographic multi-sig would be coordinated off-chain of course, but one could coordinate off-chain even without a cryptographic multi-sig, and place all the signatures into one transaction.

All the above are "difficult" in the sense that everything happens closer to the user, which requires the UX be more advanced, and maybe the UX people have more exciting lives.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Proposed Is awaiting 3 formal reviews.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants