-
Notifications
You must be signed in to change notification settings - Fork 65
feat(sharding): put in agreement with styleguide and port code samples to Tolk #2131
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,80 +5,153 @@ title: "Contract sharding" | |||||||||||||||
| import { Aside } from '/snippets/aside.jsx'; | ||||||||||||||||
| import { Image } from '/snippets/image.jsx'; | ||||||||||||||||
|
|
||||||||||||||||
| Some protocols need to store a lot of information in contracts, for example, tokens that have many users. In TON, there is a limit on how much can be stored in a single contract. The solution in TON is to split the data across many different contracts, where you can quickly find the right contract by a key and retrieve the required information from it. | ||||||||||||||||
| Some protocols need to store a lot of information in contracts, for example, token contracts with many users. In TON, there is a limit on how much can be stored in a single contract. The solution is to split the data across multiple contracts. | ||||||||||||||||
|
|
||||||||||||||||
| In such protocols, there is a child contract that initially contains the information identified by a key. In some protocols, it is important to know the Parent contract, which acts as the information manager. | ||||||||||||||||
| Each such contract, referred to as a child contract, is associated with a key that allows direct access to the required contract and its data. Some protocols also introduce a _parent_ contract that coordinates child contracts. | ||||||||||||||||
|
|
||||||||||||||||
| To avoid having to know the key upfront, we do not populate that field in `StateInit`; we only populate the key field. This makes it easy to locate the required contract later. | ||||||||||||||||
| ## Child contract address by key | ||||||||||||||||
|
|
||||||||||||||||
| The contract address depends on the initial data provided in [`StateInit`](/foundations/messages/deploy). To ensure that a child contract can be accessed using only the key, the initial data includes the key but does not include the associated value. As a result, the address of the child contract can be determined from the key alone. | ||||||||||||||||
|
Comment on lines
+12
to
+14
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [HIGH] Missing code font for
|
||||||||||||||||
| ## Child contract address by key | |
| The contract address depends on the initial data provided in [`StateInit`](/foundations/messages/deploy). To ensure that a child contract can be accessed using only the key, the initial data includes the key but does not include the associated value. As a result, the address of the child contract can be determined from the key alone. | |
| ## Child contract address by key | |
| The contract address depends on the initial data provided in [`StateInit`](/foundations/messages/deploy). To ensure that a child contract can be accessed using only the key, the initial data includes the key but does not include the associated value. As a result, the address of the child contract can be determined from the key alone. |
Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[HIGH] Casing of “jetton” at sentence start
| ## NFT and jetton examples | |
| Consider NFTs: the collection acts as the parent contract, and each NFT item is a child contract. The key in this case is the item index, and only the collection can set the initial owner. | |
| For jettons, the parent contract is the minter, and the child contracts are user wallets. The key is the user's smart contract address, and the value is the user's token balance. | |
| Both patterns follow the same principle: each key maps to a separate contract. In jetton protocols, there is a unique contract per user, while in NFT collections, there is one contract per item (by index) that is shared across all users. |
Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the child StateInit only includes seqno, so two parents using the same child code and sequence number can derive the same child address. it also contradicts the caution above, because the child has no stored parent address to verify
to fix it is to include the parent address in the child's initial storage, pass it into address derivation, and verify it in the child handler
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure, but I think the else branch in the match below may not be reachable as written. Since TodoChildMessage = Identify is a single-variant union, lazy TodoChildMessage.fromSlice(in.body) should throw on any body that doesn't parse as Identify - including an empty body, since the opcode parse fails first
If the intent is to ignore empty top-up messages, the empty-body check probably needs to happen before the lazy fromSlice call for instance
fun onInternalMessage(in: InMessage) {
+ if (in.body.isEmpty()) {
+ return;
+ }
val msg = lazy TodoChildMessage.fromSlice(in.body);it definitely worths double-checking against actual Tolk semantics
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DeployAnother is accepted from any sender and spends ton("0.1") from the parent. If copied as-is, anyone can repeatedly trigger child deployments and drain the parent balance
either mark this handler as demo-only, or add authorization. For example:
struct TodoParentStorage {
+ // Initialize this field in the parent's StateInit during deployment.
+ adminAddress: address
numChildren: uint64 = 0
// Parent must know the child contract code to deploy new instances.
todoChildCode: cell
} DeployAnother => {
var storage = lazy TodoParentStorage.load();
+ assert (in.senderAddress == storage.adminAddress) throw 0xFFFF;
storage.numChildren += 1;There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor point: numChildren increments before the send, and the send uses SEND_MODE_IGNORE_ERRORS. If the action fails to queue, the counter still bumps, so the next deploy uses seqno = N+2 and leaves a gap
absolutely not a bug if contiguous numbering doesn't matter, but might be worth a sentence in the prose or a short comment in the sample so readers don't assume sequence numbers are guaranteed dense :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the createMessage call omits explicit bounce behavior. The Tolk message docs say createMessage should specify bounce behavior, and the full examples in this repo do so
https://docs.ton.org/languages/tolk/features/message-handling#bouncemode-in-createmessage
I'd add an explicit mode, for example:
val deployMsg = createMessage({
+ bounce: BounceMode.Only256BitsOfBody,
dest: calcDeployedTodoChild(
storage.numChildren,
storage.todoChildCode,
),
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"a key that allows direct access to the required contract and its data" repeats "contract" a bit awkwardly. it makes sense to read cleaner as something like:
a key that uniquely determines its address