github.com/NebulousLabs/Sia@v1.3.7/doc/Developers.md (about) 1 Developer Environment 2 ===================== 3 4 Sia is written in Go. To build and test Sia, you are going to need a working go 5 environment, including having both `$GOROOT/bin` and `$GOPATH/bin` in your 6 `$PATH`. For most Linux distributions, Go will be in the package manager, 7 though it may be an old version that is incompatible with Sia. Once you have a 8 working Go environment, you are set to build the project. If you plan on cross 9 compiling Sia, you may need to install Go from source. You can find information 10 on that [here](http://golang.org/doc/install/source). 11 12 Sia has a development build, an automated testing build, and a release 13 build. The release build is the only one that can synchronize to the full 14 network. To get the release build, it is usually sufficient to run `go get -u 15 github.com/NebulousLabs/Sia/...`. This will download Sia and its dependencies 16 and install binaries in `$GOPATH/bin`. 17 18 After downloading, you can find the Sia source code in 19 `$GOPATH/src/github.com/NebulousLabs/Sia`. To build the release binary, run 20 `make release-std` from this directory. To build the release binary with a 21 (slow) race detector and an array of debugging asserts, run `make release`. To 22 build the developer binary (which has a different genesis block, faster block 23 times, and a few other tweaks), just run `make`. 24 25 If you intend to contribute to Sia, you should start by forking the project on 26 GitHub, and then adding your fork as a "remote" in the Sia git repository via 27 `git remote add [fork name] [fork url]`. Now you can develop by pulling changes 28 from `origin`, pushing your modifications to `[fork name]`, and then making a 29 pull request on GitHub. 30 31 If you see an error like the one below, it means that you either forgot to run 32 `make dependencies`, or you cloned the project into a path that the go tool 33 does not recognize (usually the wrong path, or symbolic links were somehow 34 involved). 35 36 ``` 37 consensus/fork.go:4:2: cannot find package "github.com/NebulousLabs/Sia/crypto" in any of: 38 /usr/lib/go/src/github.com/NebulousLabs/Sia/crypto (from $GOROOT) 39 /home/user/gopath/src/github.com/NebulousLabs/Sia/crypto (from $GOPATH) 40 ``` 41 42 Developer Conventions 43 ===================== 44 45 This file is meant to help a developer navigate the codebase and develop clean, 46 maintainable code. Knowing all of these conventions will also make it easier to 47 read and code review the Sia project. 48 49 The primary purpose of the conventions within Sia is to keep the codebase 50 simple. Simpler constructions means easier code reviews, greater accessibility 51 to newcomers, and less potential for mistakes. It is also to keep things 52 uniform, much in the spirit of `go fmt`. When everything looks the same, 53 everyone has an easier time reading and reviewing code they did not write 54 themselves. 55 56 Documentation 57 ------------- 58 59 All structs, functions, and interfaces must have a docstring. 60 61 Anytime that something is left unfinished, place a comment containing the 62 string 'TODO:'. This sends a clear message to other developers, and creates a 63 greppable way to find unfinished parts of the codebase. 'TODO' statements are 64 currently discouraged. As the codebase matures, 'TODO' statements will become 65 increasingly frowned upon. 'TODO' statements should not document feature 66 requests, but instead document incompleteness where the incompleteness causes 67 disruption to user experience or causes a security vulnerability. 68 69 Documentation should give a sense of what each function does, but should also 70 give a sense of the overall architecture of the code. Where useful, examples 71 should be provided, and common pitfalls should be explained. Anything that 72 breaks other conventions in any way needs to have a comment, even if it is 73 obvious why the convention had to be broken. 74 75 The goal of the codebase is to be accessible to newbies. Anything more advanced 76 than what you would expect to remember from an 'Intro to Data Structures' class 77 should have an explanation about what the concept it is and why it was picked 78 over other potential choices. 79 80 Code that exists purely to be compatible with previous versions of the 81 software should be tagged with a `COMPATvX.X.X` comment. Examples below. 82 83 ```go 84 // Find and sort the outputs. 85 outputs := getOutputs() 86 // TODO: actually sort the outputs. 87 ``` 88 89 ```go 90 // Disallow unknown agents. 91 // 92 // COMPATv0.4.0: allow a blank agent to preserve compatibility with 93 // 'siac' v0.4.0, which did not set an agent. 94 if agent != "SiaAgent" && agent != "" { 95 return errors.New("unrecognized agent!") 96 } 97 ``` 98 99 Naming 100 ------ 101 102 Names are used to give readers and reviewers a sense of what is happening in 103 the code. When naming variables, you should assume that the person reading your 104 code is unfamiliar with the codebase. Short names (like `cs` instead of 105 `consensusSet`) should only be used when the context is immediately obvious. 106 For example `cs := new(ConsensusSet)` is immediately obvious context for `cs`, 107 and so `cs` is appropriate for the rest of the function. 108 109 Data structures should never have shortened names. `FileContract.mr` is 110 confusing to anyone who has not used the data structure extensively. The code 111 should be accessible to people who are unfamiliar with the codebase. One 112 exception is for the variable called `mu`, which is short for 'mutex'. This 113 exception is made because `mu` appears in many data structures. 114 115 When calling functions with obscure parameters, named variables should be used 116 to indicate what the parameters do. For example, `m := NewMiner(1)` is 117 confusing. Instead, use `threads := 1; m := NewMiner(threads)`. The name gives 118 readers a sense of what the parameter within `NewMiner` does even when they are 119 not familiar with the `NewMiner` function. Where possible, functions with 120 obscure, untyped inputs should be avoided. 121 122 The most important thing to remember when choosing names is to cater to people 123 who are unfamiliar with the code. A reader should never have to ask 'What is 124 `cs`?' on their first pass through the code, even though to experienced 125 developers it is obvious that `cs` refers to a `consensus.ConsensusSet`. 126 127 ### Function Prefixes 128 129 Sia uses special prefixes for certain functions to hint about their usage to the 130 caller. 131 132 #### `threaded` 133 134 Prefix functions with `threaded` (e.g., `threadedMine`) to indicate that callers 135 should only call these functions within their own goroutine (e.g., 136 `go threadedMine()`). These functions must manage their own thread-safety. 137 138 #### `managed` 139 140 Prefix functions with `managed` (e.g. `managedUpdateWorkerPool`) if the function 141 acquires any locks in its body. 142 143 Control Flow 144 ------------ 145 146 Where possible, control structures should be minimized or avoided. This 147 includes avoiding nested if statements, and avoiding else statements where 148 possible. Sometimes, complex control structures are necessary, but where 149 possible use alternative code patterns and insert functions to break things up. 150 151 Example: 152 153 ```go 154 // Do not do this: 155 if err != nil { 156 return 157 } else { 158 forkBlockchain(node) 159 } 160 161 // Instead to this: 162 if err != nil { 163 return 164 } 165 forkBlockchain(node) 166 ``` 167 168 Mutexes 169 ------- 170 171 All exported functions from a package and/or object need to be thread safe. 172 Usually, this means that the first lines of the function contain a `Lock(); 173 defer Unlock()`. Simple locking schemes should be preferred over performant 174 locking schemes. As will everything else, anything unusual or convention 175 breaking should have a comment. 176 177 Non-exported functions should not do any locking unless they are named with the 178 proper prefix (see [Function Prefixes](#function-prefixes)). The responsibility 179 for thread-safety comes from the exported functions which call the non-exported 180 functions. Maintaining this convention minimizes developer overhead when working 181 with complex objects. 182 183 Error Handling 184 -------------- 185 186 All errors need to be checked as soon as they are received, even if they are 187 known to not cause problems. The statement that checks the error needs to be 188 `if err != nil`, and if there is a good reason to use an alternative statement 189 (such as `err == nil`), it must be documented. The body of the if statement 190 should be at most 4 lines, but usually only one. Anything requiring more lines 191 needs to be its own function. 192 193 Example: 194 195 ```go 196 block, err := s.AcceptBlock() 197 if err != nil { 198 handleAcceptBlockErr(block, err) 199 return 200 } 201 ``` 202 203 Sanity Checks 204 ------------- 205 206 Some functions make assumptions. For example, the `addTransaction` function 207 assumes that the transaction being added is not in conflict with any other 208 transactions. Where possible, these explicit assumptions should be validated. 209 210 Example: 211 212 ```go 213 if build.DEBUG { 214 _, exists := tp.usedOutputs[input.OutputID] 215 if exists { 216 panic("incorrect use of addTransaction") 217 } 218 } 219 ``` 220 221 In the example, a panic is called for incorrect use of the function, but only 222 in debug mode. This failure will be invisible in production code, but the code 223 will have higher performance because the code should never fail anyway. 224 225 If the code is continually checking items that should be universally true, 226 mistakes are easier to catch during testing, and side effects are less likely 227 to go unnoticed. 228 229 Sanity checks and panics are purely to check for developer mistakes. A user 230 should not be able to trigger a panic, and no set of network communications or 231 real-world conditions should be able to trigger a panic. 232 233 Testing 234 ------- 235 236 The test suite code should be the same quality as the rest of the codebase. 237 When writing new code in a pull request, the pull request should include test 238 coverage for the code. 239 240 Most modules have a tester object, which can be created by calling 241 `createXXXTester`. Module testers typically have a consensus set, a miner, a 242 wallet, and a few other relevant modules that can be used to build 243 transactions, mine blocks, etc. 244 245 In general, testing that uses exclusively exported functions to achieve full 246 coverage is preferred. These types of tests seem to find more bugs and trigger 247 more asserts. 248 249 Any testing provided by a third party which is both maintainable and reasonably 250 quick will be accepted. There is little downside to more testing, even when the 251 testing is largely redundant.