Confusion about smart contracts

Dear Guys
I have a problem while learning smart contracts, how can I write and read data structures automatically through smart contracts?
The data type byte “counter” in the example does not match what I want. Is there a function to define data types in Algorand smart contracts?

Stateful smart contracts use key/value storage.
Each value can store either a byte string or a 64-bit unsigned integer.

If you need to store more complex data structure, you need to manually implement them.

What kind of data structure are you interested in?

1 Like

Thanks,fabrice.
The key-value pair is exactly what I need, but I may need to store more than one key-value pair, e.g. [student-{1,2,3,4,5}], [teacher-{2,3,4,5,6}]…
How do I set this manually?
By the way, when I read the global status of the example byte “counter”, why the result is [{Y291bnRlcg== { 2 1}}]
What is the meaning of this result?

Do you want to store values associated to keys student-1, student-2, … ?
If yes, you need to manually generate the key using TEAL and then use the appropriate op-code to store in the value you want in this key.

Most likely, instead of student-1, you want student-#, where # is a byte equal to 1 (that is a character that cannot be displayed but that can be used as part of the key).

Note that you can store at most 64 global key/values per smart contract.
If you need more, you need to use local state.

What are you trying to store/achieve?

Can you show the code of the smart contract and the way you use to read this value?

My guess is that you printed only the value of the struct representation the global state rather than pretty-printing the actual struct.
Indeed:

  • Y291bnRlcg== is the base64 encoding of counter. See Base64 - Wikipedia. You can convert base64 on the command line like this:
base64 -d <<< "Y291bnRlcg=="
  • 2 and 1 are most likely the fields of tt (type) and ui (actual data). tt=2 means it is an integer value (as opposed to bytes), and ui=1 means that the value of the counter is 1.

Thank you very much for your guidance!

I think it is the second one that should be implemented, the trouble is that my value type is a structure
For example my key-value pair is device_id-{mac_address, device_type}, the concrete example is 123-{2567, 1}.
Can Algorand smart contract implement such data structure? I have tried it in Ethereum.

Regarding the second question, I think it should be your explanation

You need to decide of a format.
For example, if the value is mac_address, device_type, you can decide the value to be the concatenation of both with a space:

00:1B:44:11:3A:B7 macOS

for example.
You can generate it using the concat opcode (Opcodes - Algorand Developer Portal).
You can do the reverse operation using the substring opcode since the MAC address is always the same length.

You may decide to encode the MAC address as 6 bytes rather than 17 bytes.
This is more compact.
You may also remove the space.

Note that this technique only work as long as all the fields in your structure have a constant length (the MAC address has a known length of 17 bytes or 6 bytes). If this is not the case, you need more advanced encoding. For example, you can start with 1 byte indicating the length of the field.

Thank you
I understand your point in general, but I may need some time to digest it

Hey, fabrice.

I am very happy to have a better understanding of the second question.
As far as I know, the “counter” I entered is the key of a key-value pair, but I don’t know at which step of my smart contract I get the value 1 and the type 2.
By the way, if I want to use sdk to output the actual structure of the key-value pair, for example

{
  "counter": {
    "tt": 2,
    "ui": 1
  }

what should I do?

Also my smart contract code and the way I read the values is as follows.

// read global state
byte "counter"
dup 
app_global_get 

// increment the value
int 1
+

// store to scratch space
dup
store 0 
// update global state
app_global_put 
// load return value as approval
load 0 
return
func readGlobalState(client *algod.Client, account crypto.Account, index uint64) {
	accountInfo, err := client.AccountInformation(account.Address.String()).Do(context.Background())
	if err != nil {
		fmt.Printf("Error getting account info: %s\n", err)
		return
	}
	for _, ap := range accountInfo.CreatedApps {
		if ap.Id == index {
			fmt.Printf("Global state for app-id %d:\n", ap.Id)
			fmt.Println(ap.Params.GlobalState)
		}
	}
}

To print structure in GoLang:

fmt.Printf("%#v", ap.Params.GlobalState)

or:

    gs, err := json.MarshalIndent(ap.Params.GlobalState, "", "\t")
    if err != nil {
        fmt.Printf("Can not marshall global state data: %s\n", err)
    }
    fmt.Printf("%s\n", gs)

Thanks for your help