These rules are targeted for the Cosmos-sdk to catch common mistakes that could be devasting.
- Unsafe imports
- strconv unsigned integers cast to signed integers overflow
- Non deterministic map iteration
Imports like unsafe, runtime and math/rand are potential sources of non-determinism and hence they are flagged when in code.
Parsing signed integers consumes one bit less than their unsigned counterparts. The usage of strconv.ParseUint to parse a signed integer
out of a string returns an unsigned 64-bit integer uint64
. This uint64
if cast with the wrong constant bitsize is now flagged, for example the following
u64, err := strconv.ParseUint(str, 10, 64)
if err != nil {
panic(err)
}
i64 := int64(u64)
which ideally should have been
u64, err := strconv.ParseUint(str, 10, 63)
if err != nil {
panic(err)
}
i64 := int64(u64)
In Go, iterating over maps is intentionally non-deterministic as the runtime defines. Unfortunately for us, in the Cosmos-SDK, we encountered an issue with non-deterministic upgrades in Issue cosmos-sdk#10188 PR cosmos-sdk#10189 that resulted from exactly this non-deterministic iteration. To ensure determinism, we only permit an iteration to retrieve the map keys and then those keys can then be sorted, so instead of
for k, v := range m {
// Do something with key and value.
_, _ = k, v
}
the requested pattern is instead
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
for _, key := range keys {
// Use the value.
_ = m[key]
}