Common Gotchas
Use this page when you want the shortest list of things most likely to break an implementation.
1. Treat tsdk_return and tsdk_revert as terminal
Section titled “1. Treat tsdk_return and tsdk_revert as terminal”They both end execution through tsys_exit. Any code after them is unreachable.
2. Do not trust account indices from instruction payloads
Section titled “2. Do not trust account indices from instruction payloads”Always run tsdk_is_account_idx_valid(...) before reading metadata, data pointers, or issuing syscalls with an account index taken from instruction bytes.
3. A data pointer is not the same thing as writable permission
Section titled “3. A data pointer is not the same thing as writable permission”tsdk_get_account_data_ptr(...) gives you an address, not permission. If you intend to mutate data, the account usually needs to be writable in context, and many flows should call tsys_set_account_data_writable(...) first.
4. tsys_invoke has two failure channels
Section titled “4. tsys_invoke has two failure channels”Check both:
- the syscall return value
- the callee error in
invoke_err_code
Ignoring one of them causes misleading CPI behavior.
5. Auth entries for CPI must be owned by the current program
Section titled “5. Auth entries for CPI must be owned by the current program”The wrapper validates this before the syscall and can revert locally if you authorize an account your program does not own.
6. State proofs are variable-size
Section titled “6. State proofs are variable-size”Do not use sizeof( tsdk_state_proof_t ) as the received proof length. Read the header and call tsdk_state_proof_footprint_from_header(...).
7. Transaction and proof structs are layout-sensitive
Section titled “7. Transaction and proof structs are layout-sensitive”Several public structs are packed or represent wire-aligned layouts. Avoid casual casting from arbitrary byte buffers without checking size and alignment assumptions.
8. tsdk_printf is for debugging, not unlimited output
Section titled “8. tsdk_printf is for debugging, not unlimited output”It formats into a fixed local buffer and ultimately logs through tsys_log.
9. Prefer helper accessors over manual VM address math
Section titled “9. Prefer helper accessors over manual VM address math”The segment constants and TSDK_ADDR(...) are public, but most tasks are safer with helpers like tsdk_get_txn, tsdk_get_account_meta, and tsdk_get_current_block_ctx.
10. Start with tn_sdk.h unless the task is clearly lower level
Section titled “10. Start with tn_sdk.h unless the task is clearly lower level”Agents can easily overcomplicate C SDK usage by pulling in too many low-level headers too early. The umbrella include is the right default.
11. Build against the installed SDK, not the repo-local SDK internals
Section titled “11. Build against the installed SDK, not the repo-local SDK internals”For end-user workflows, prefer:
thru dev toolchain installthru dev sdk install cthru_c_program.mk
not direct reliance on repo-local setup scripts.
12. Keep entrypoints thin
Section titled “12. Keep entrypoints thin”Large monolithic entrypoints make it harder for both humans and agents to reason about validation and mutation ordering. Validate early, dispatch quickly, and push real logic into helpers.