Since it looks like we are soon finalizing the concepts for our cryptographic commitment primitives (epoch commitment chains), I believe we now have all the high level building blocks to start speccing a more concise fluid sharding framework.
Everything that I am going to propose builds on top of my earlier proposal of “untangling the tangle” by introducing shard markers as a coordinate for outputs and transactions in a sharding space (see Scaling IOTA Part 2 - Untangling the Tangle | by Hans Moog | Medium).
This coordinate system allows us to define a “location for the data and the execution” and can be used to associate different regions of the tangle with different groups of responsible nodes similar to a DHT (distributed hash table).
Let’s for now assume the sharding space is a cyclical structure e.g. a 32 bytes hash where the last value of the hash is right next to the first one:
For simplicity reasons, we can imagine to unroll this cyclical structure into a 1-dimensional representation:
In contrast to my earlier proposal where things were completely fluid, we introduce an overlay topology which defines fixed regions of this shard space that will make up the shards (similar to the “epishards” earlier proposed by Bart). Let’s for now assume we slice the tangle into 8 equal parts and enumerate these shards from 0 to 7 (an arbitrary number - we can introduce protocols and mechanism to automatically adjust this topology based on demand later on and a 32 byte hash gives us potentially 2^256 - 1 shards):
Nodes can still freely decide how many and which shards they want to monitor but they need to monitor at least 3 consecutive shards (more on that later):
Each of these shards will produce their own cryptographic commitment chain comitting to their respective activity.
Since each commitment is associated to some “space coordinate” in the sharding space but also to some “time coordinate” in respect to “passed epochs since genesis” - we associate each commitment with a space/time coordinate:
So far, the commitment is a merkle root over all of the “sub-roots” of a given epoch (included messages, confirmed txs, ledger state and so on) and we can use this commitment to produce succinct proofs inside a shard:
Commitment(space/time) = MerkleRoot(stateRoots_{space/time})
We now want to extend this definition to also capture information of other shards. For this, we change the definition of a commitment in the following way:
Commitment(space/time) = MerkleRoot(
\>\>\>\>\>\>\>\>Commitment(space -1/time - 1),
\>\>\>\>\>\>\>\>MerkleRoot(stateRoots_{space/time}),
\>\>\>\>\>\>\>\>Commitment(space + 1/time - 1)
)
This results in a situation where each commitment doesn’t just commit to the activity of its own shard but also to the previous commitment of its neighboring shards (left and right) - forming something like a meta-tangle of commitments wrapping around the entire tangle like a mesh and indirectly connecting all existing shards:
Since each commitment is just a single hash, all nodes can download this entire meta-tangle giving them access to the state commitments of all other shards. This meta-tangle essentially forms the equivalent of ETH’s beacon chain.
Since the commitment tangle is circular, each space/time coordinate that is sufficiently old is reachable through both paths (left and right). Nodes can use this information to validate that the commitments they see from one side of the network match with the commitments they see from the other side.
This prevents malicious shards from presenting different commitments to different “sides” of the shard space so the only thing a malicious shard could do is to create a fraudulent commitment and this should ideally be addressed with some fisherman algorithm that allows actors to create fraud proofs for the commitments of other shards while they are propagating - resulting in a better 1 of N trust assumption (ideally prior to notarization).
As soon as a space/time coordinate is referenced by our own chain, it becomes “known to us” and we can “access” this space-time coordinate for proofs of inclusion which enables inter-shard transactions:
To send a transaction to another shard, we simply create a transaction in the originating shard that moves the funds to the given destination shard. This transaction is only processed in the originating shard but since the resulting state is no longer relevant for this shard, nodes will only include the state in their commitment but will no longer store the actual metadata of the Output (the output becomes unspendable in the originating shard - we essentially burn its funds).
As soon as the space/time coordinate that represents the containing commitment is known to the destination shard, the moved output can be presented to the destination shard together with a proof of inclusion against the corresponding space/time coordinate. This will allows us to mint the moved tokens in the destination shard.
Of course moving funds between distant shards will take a certain amount of time that is dependent on the amount of shards that exist + the interval at which we produce commitments.
To enable faster real-time payments between distant shards we introduce a new unlock condition for outputs:
The output can only be unlocked if:
- a given public key signed the transaction and the issuer can present a “proof of inclusion” of a certain state (its hash) in an earlier commitment of the same shard
- alternatively after some time it can be unlocked by an alternative public key without such a proof.
Furthermore we assume that there will be service providers that will want to provide the ability to move funds between distant shards in real-time for some small fee and that these service-providers will be incentivized enough to operate at least 1 node in each shard.
What users can do now is to approach these service providers and negotiate a FEE payed in IOTA that will be payed for instantly moving a certain AMOUNT of funds to another shard. They will accordingly send the funds to an Output in the destination shard that has the unlock condition, that the public key of the service provider can spend the output, if he can prove that he sent AMOUNT - FEE funds to a certain address in an earlier transaction.
The service provider can now wait for a transaction to be confirmed in the originating shard and since he knows that it will become part of the next epoch commitment, he can hand out the funds in the destination shard immediately. He will later be able to reimburse his expense by collecting the entire funds (including the fee) by claiming it from the state commitment.
If the service provider does not send the funds or does not provide the proof that he sent the funds before the timelock expires, the user can unlock the funds and recover his tokens.
This whole process is accordingly completely trustless and is essentially equivalent, to how optimistic rollups enable fast withdrawals.
I think that we can most probably enhance these concepts with things like data availability sampling and or maybe sampling the honesty of other shards via SPV but especially early on when the tangle is not too fragmented yet this should already be sufficient to enable a first version of fluid sharding.
Eventually this can also be combined with ZkProofs on L1, so that every message effectively validates the entire tangle + history. The recursive nature of zkproof systems like plonky matches exactly the structure of our meta-tangle.
so TL;DR:
- we entangle the commitments to form a beacon-tangle that is tracked by all nodes.
- we burn funds moved to another shard in the originating shard and mint them in the destination shard after proving the state was included in the corresponding space/time commitment.