Full Report
Several folks wrote about issues to look for in Cosmos-based blockchains. I have a personal list of these but it's nice to see a large external list! Cosmos is built via writing Go code at the infrastructure layer, as opposed to writing code in a virtual machine like the EVM. This creates many unique issues. The first mentioned class is non-determinism. If different groups of validators see different proofs at the end of execution of a transaction then the blockchain will come to a halt. Randomness, Go maps (randomly determine where to start in a map), timestamps from the local machine, concurrency and floats by different platforms. The second class are in protocol panics. Code executes within the BeginBlock/EndBlock that panics will lead to a chain halt. Hence, panics should be handled in a nice way. This can happen via bad math operations, bulk coin sends for blacklisted addresses and added in panics. A third thing to watch out for is unmetered computation. Only stateful things have gas meters. For instance, reading/writing to state within a callable message. However, BeginBlock/EndBlock do not. So, if a user can setup code to end in these locations, it can be real bad. Additionally, bad loops on non-state operations can cause halts as well. The next one is Key Malleability and Prefix Iteration. In Cosmos, all state is simply a key-value store. For storage, it's recommended to add a prefix to a data type so that you don't overwrite the wrong things or create collisions. Even checking for existence by a prefix needs to be done carefully. I remember thinking about these collisions myself but most developers are smart enough to add a large string to the beginning of the data to signify a datatype. An iterator is created for going through a KVS space. When using an iterator, adding the prefix to the store is crucial. Otherwise, unintended data could be iterated over the top of. Iterators are inclusive of the first byte but exclusive of the end byte. So, this can create a bad iterators over the top of data. Cosmos developers need to consider gas. The KVS does contain automatic gas charging for storage reads and writes but sometimes more needs to be done. However, adding more gas for specific operations can be necessary to prevent spam. Cosmos is known to have high levels of congestion and not having a good way of handling this during peak load. The gas stuff on Cosmos feels like a blackbox to me atm. Overall, a good series of issues! They're going to do a CosmWasm and IBC post in the future, which will be good for everyone in the space. I look forward to seeing the post and adding to my list of test cases on Cosmos based blockchains.
Analysis Summary
# Best Practices: Cosmos Core Chain Development
## Overview
These practices address the unique security risks associated with building application-specific blockchains (AppChains) using the Cosmos SDK. Because Cosmos allows developers to write code at the infrastructure layer (Go) rather than a constrained Virtual Machine (like EVM), it introduces critical vulnerabilities related to consensus stability, state machine integrity, and resource management.
## Key Recommendations
### Immediate Actions
1. **Eliminate `time.Now()`:** Replace all instances of local machine time with `ctx.BlockTime()` to ensure temporal determinism across validators.
2. **Audit Go Maps:** Scan the codebase for any iteration over Go maps within the state machine. Replace with sorted slices to prevent non-deterministic execution.
3. **Remove `panic` in State Logic:** Ensure `BeginBlock` and `EndBlock` do not contain code that can trigger a panic (e.g., division by zero, nil pointer dereference), as this will halt the entire network.
4. **Enforce Key Separation:** Ensure every data type in the Key-Value Store (KVS) uses a unique, hardcoded prefix to prevent key collisions.
### Short-term Improvements (1-3 months)
1. **Gas Metering Audit:** Identify all loops and heavy computations within the state machine. Manually implement gas consumption for operations that do not automatically trigger the SDK’s store-based gas meter.
2. **Safe Iterator Implementation:** Review all KVS iterators. Ensure they use `sdk.PrefixEndBytes` correctly and handle the inclusive/exclusive nature of byte ranges to avoid "bleeding" into adjacent data types.
3. **Input Validation for KVS:** Implement strict length checks or fixed-width encoding (e.g., BigEndian for integers) for keys to prevent "Key Malleability" (where one key appears as a prefix of another).
### Long-term Strategy (3+ months)
1. **Deterministic Testing Framework:** Build a test suite specifically designed to check for state drift across different architectures (floats, different OS builds).
2. **Fee Market Hardening:** Implement advanced congestion management and anti-spam mechanisms to protect the chain during high-load periods.
3. **Formal Verification of State Transitions:** For critical modules (like token transfers), use formal methods to ensure state updates are atomic and error-resistant.
---
## Implementation Guidance
### For Small Organizations
* **Focus on the "No-Go" List:** Strictly forbid the use of the `rand` package, floating-point math, and `goroutines` in the state machine.
* **Use SDK Standards:** Stick to the `types` provided by the Cosmos SDK (e.g., `sdk.Int`) which handle overflow and math safely.
### For Medium Organizations
* **Standardize Key Encoding:** Enforce a team-wide standard for KVS keys, such as using `Uint64ToBigEndian` for all ID-based keys to ensure consistent key lengths and prevent prefix overlaps.
* **External Audits:** Prioritize auditing `BeginBlocker` and `EndBlocker` logic, as these are the most common vectors for unmetered computation attacks.
### For Large Enterprises
* **Custom Gas Modules:** Develop sophisticated gas charging for non-state operations (computationally expensive logic) to prevent localized DoS.
* **Multi-Platform CI/CD:** Run consensus tests on multiple hardware architectures to catch non-determinism caused by low-level Go or platform differences.
---
## Configuration Examples
### Correct Integer Key Encoding
Avoid string-based integer conversion to prevent prefix collisions (e.g., "42" being a prefix of "421").
go
// Safe: Fixed-width BigEndian encoding
func GetKey(id uint64) []byte {
bz := make([]byte, 8)
binary.BigEndian.PutUint64(bz, id)
return bz
}
### Handling Non-Deterministic Map Iteration
go
// Unsafe: range map
// Safe: Extract keys, sort them, then iterate
keys := make([]string, 0, len(myMap))
for k := range myMap {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
process(myMap[k])
}
---
## Compliance Alignment
* **NIST SP 800-193:** (Platform Firmware Resiliency) - Relevant to maintaining consensus integrity.
* **ISO/IEC 27001:** Controls for integrity and availability of information systems.
* **CIS Benchmarks:** General secure coding standards for Go-based infrastructure.
---
## Common Pitfalls to Avoid
* **The "Blacklist" Panic:** Triggering a panic when a bulk coin send hits a blacklisted address. Always use "Return Error" instead of "Panic" in transaction handlers.
* **Floating Point Math:** Using `float32` or `float64`. Different CPUs handle rounding differently, leading to chain forks. Use `sdk.Dec` or `sdk.Int`.
* **Unmetered Iterators:** Running an iterator over an unbounded set of keys without consuming gas per item, leading to a "Block Gas Limit" bypass.
---
## Resources
* **Cosmos SDK Documentation:** [hXXps://docs.cosmos.network]
* **Cosmos SDK Determinism Appendix:** (Consult the official SDK developer guide)
* **Go Map Iteration Internals:** [hXXps://medium.com/i0exception/map-iteration-in-go-275abb76f721]