From 2eb5fab4550c9cc92c06b22d2169fde5e0c4aa08 Mon Sep 17 00:00:00 2001
From: Emmanuel T Odeke <emmanuel@orijtech.com>
Date: Wed, 10 Nov 2021 18:11:03 +0000
Subject: [PATCH] rules/sdk: add a README

Documents the rules we've defined for the cosmos-sdk
---
 rules/sdk/README.md | 59 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 rules/sdk/README.md

diff --git a/rules/sdk/README.md b/rules/sdk/README.md
new file mode 100644
index 0000000..0259414
--- /dev/null
+++ b/rules/sdk/README.md
@@ -0,0 +1,59 @@
+## cosmos-sdk rules
+
+These rules are targeted for the [Cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to catch common mistakes that could be devasting.
+
+### Table of contents
+- [Unsafe imports](#unsafe-imports)
+- [strconv unsigned integers cast to signed integers overflow](#strconv-unsigned-integers-cast-to-signed-integers-overflow)
+- [Non deterministic map iteration](#non-deterministic-map-iteration)
+
+### Unsafe imports
+Imports like [unsafe](https://golang.org/pkg/unsafe), [runtime](https://golang.org/pkg/runtime) and [math/rand](https://golang.org/pkg/math/rand) are potential sources of non-determinism
+and hence they are flagged when in code.
+
+### strconv unsigned integers cast to signed integers overflow
+Parsing signed integers consumes one bit less than their unsigned counterparts. The usage of [strconv.ParseUint](https://golang.org/pkg/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
+
+```go
+    u64, err := strconv.ParseUint(str, 10, 64)
+    if err != nil {
+        panic(err)
+    }
+    i64 := int64(u64)
+```
+
+which ideally should have been
+
+```go
+    u64, err := strconv.ParseUint(str, 10, 63)
+    if err != nil {
+        panic(err)
+    }
+    i64 := int64(u64)
+```
+
+### Non deterministic map iteration
+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](https://github.com/cosmos/cosmos-sdk/issues/10188) [PR cosmos-sdk#10189](https://github.com/cosmos/cosmos-sdk/pull/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
+```go
+for k, v := range m {
+    // Do something with key and value.
+    _, _ = k, v
+}
+```
+
+the requested pattern is instead
+```go
+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]
+}
+```