After some experience about Hyperledger Fabric and Ethereum, I “landed” to Algorand. I’m yet learning and I develop a first little application able to write a simple “hello world” in the testNet. Then, I replaced the simple “hello world” with a json payload (just a few lines) and I received an error related to the exceeding the maximum block size.
What am I doing wrong? Or what am I missing?
The error you’ve shared talks about access budget for boxes. Essentially each box reference you include with the application transaction provides up to 1K of write budget. With budget pooling you can include the same reference multiple times to increase the budget. So if you were to include the box reference twice you’ll have up to 2K of write budget. You can include up to 8 box references per transaction, and it’s also shared across transactions within the same group.
Hi, thank you for your answer. So it is possible to increase the maximum box size, what is not totally clear to me is where to implement this part, in the smart contract or on the sdk that calls it? Is there by any snippet online that shows how to do it?
I understand that anyway the limit is 8k, even instantiating 8 box storage, so if I wanted to store a 9k json I couldn’t do that?
What does creating multiple box storage entail? Do I have to split my document into multiple parts and then store them? Wouldn’t this make later retrieval of the entire document complicated?
Also, I noticed that among the methods to manipulate the box_store, there is no method to update the entire contents of a box without the size of the new value not exactly matching the size of the old one; so assuming I want to update the value of a box with key X, does the size of the new value have to match the old size or is it possible that it is different?
It’s not possible unfortunately. One box is 32 kB max. See MaxBoxSize.
Even though one box can be as large as that, if you want to write to it you have to “spend” your box references for each kB that you write (that’s probably what you interpreted as “incresing the size”).
Each app call can write at most 8 kB of data because of 8 max references. This is true for a single isolated call, if you take box budget pooling into account you can do more.
That being said, you can write as much data to as much boxes as you like in the same contract provided that you split those writes into multiple application calls. This is the reason why boxes are sometimes called “unlimited storage”.
If you only care about notarization, you will always be able to read off-the-chain all box content as you wish with an Indexer. If you want to handle that data on-the-chain, you have to work around write/read budget of a app call transaction (and use tricks discussed earlier to be more efficient).
You can use box_replace which lets you overwrite a byte-array from the stack to a box in a particular section without having to delete and re-create a box. This can be used to create a max size box and then handle the encoding/storing of the information yourself by growing/shrinking your encoded data. Boxes are unstructured by default.
Also, keep in mind that you have a 4 kB limit for elements that are on the AVM stack.
Hi Giorgio, thank you for your reply.
Regarding the multiple reference to box_storage or “box budget pooling” is there any example we can follow to achieve this? I had a look at the documentation but I’m still having some doubts/difficulties to implement this logic in my smart contract (with the understanding that the maximum limit still remains 32kB for a single box).
How advisable might it be to use an approach like ours, i.e., storing the entire JSON on the blockchain rather than storing, for example, only the hash of the json while keeping the actual content off-chain so that it can be retrieved at the appropriate time? This would prevent us from this “workaround” involving read/write boxes, correct?
Regarding the “box_replace” method I am having some doubts, as from my testing I am noticing “anomalous” behavior which I describe below:
I get a box that will have the name chosen by me with the content also chosen; suppose I create a box with the name “test” with the content “7c39a6a8fd9eb2009c68d3865c75313d70992df420465c6c31bf2af883840c8a.” The created box will then have a length based on this content, if I try to update the content with the “box_replace” method, for example trying to insert “test” instead of the old string, what I actually get is the string “test6a8fd9eb2009c68d3865c75313d70992df420465c6c31bf2af883840c8a”, so the entire value of the old string is not replaced but the new value+the old one is put in the head. Am I doing something wrong in my method or is this normal behavior?
Same thing if I try to use the box_replace method, passing instead for example a string like this “7c39a6a8fd9eb2009c68d3865c75313d70992df420465c6c31bf2af883840c8aaaaa” I get this error:
“Network request error. Received status 400 (): TransactionPool.Remember: transaction QGNYEDCJA5HJ4VVK2XTUN5KWQD2VRURSXEB2BCH3RJXV7JPKF5AA: logic eval error: replacement end 68 beyond original length: 64. Details: pc=303, opcodes=frame_dig -1; extract 2 0; box_replace”
So I cannot insert a longer string because it exceeds the maximum size with which the box was initialized.
Yes. You can take a look here. Look for application.py and box_demo.py.
Yes this is the intended behavior of box_replace. If you wish to dynamically grow/shrink the size of the encoded data you have in your box, you can use a combination of that and other opcodes. If you wish to resize the box itself, there’s no choice other than delete and recreate.
That is to say, think of it like space on a disk. You can have a large box (disk) and have leftover bytes (free disk space). You just need some metadata about the data you are storing. Look into dynamic types in the ABI specification.
That is hard to say without expanding on your use case. We’ll have a change to talk about design in our upcoming meeting.