github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/types/block_test.go (about) 1 package types 2 3 import ( 4 "testing" 5 6 "github.com/NebulousLabs/Sia/crypto" 7 "github.com/NebulousLabs/Sia/encoding" 8 ) 9 10 // TestCalculateCoinbase probes the CalculateCoinbase function. The test code 11 // is probably too similar to the function code to be of value. 12 func TestCalculateCoinbase(t *testing.T) { 13 c := CalculateCoinbase(0) 14 if c.Cmp(NewCurrency64(InitialCoinbase).Mul(SiacoinPrecision)) != 0 { 15 t.Error("Unexpected CalculateCoinbase result") 16 } 17 18 c = CalculateCoinbase(1) 19 if c.Cmp(NewCurrency64(InitialCoinbase-1).Mul(SiacoinPrecision)) != 0 { 20 t.Error("Unexpected CalculateCoinbase result") 21 } 22 23 c = CalculateCoinbase(295000) 24 if c.Cmp(NewCurrency64(MinimumCoinbase).Mul(SiacoinPrecision)) != 0 { 25 t.Error(c) 26 t.Error(NewCurrency64(MinimumCoinbase).Mul(SiacoinPrecision)) 27 t.Error("Unexpected CalculateCoinbase result") 28 } 29 30 c = CalculateCoinbase(1000000000) 31 if c.Cmp(NewCurrency64(MinimumCoinbase).Mul(SiacoinPrecision)) != 0 { 32 t.Error(c) 33 t.Error(NewCurrency64(MinimumCoinbase).Mul(SiacoinPrecision)) 34 t.Error("Unexpected CalculateCoinbase result") 35 } 36 } 37 38 // TestCalculateNumSiacoins checks that the siacoin calculator is correctly 39 // determining the number of siacoins in circulation. The check is performed by 40 // doing a naive computation, instead of by doing the optimized computation. 41 func TestCalculateNumSiacoins(t *testing.T) { 42 c := CalculateNumSiacoins(0) 43 if c.Cmp(CalculateCoinbase(0)) != 0 { 44 t.Error("unexpected circulation result for value 0, got", c) 45 } 46 47 if testing.Short() { 48 t.SkipNow() 49 } 50 totalCoins := NewCurrency64(0) 51 for i := BlockHeight(0); i < 500e3; i++ { 52 totalCoins = totalCoins.Add(CalculateCoinbase(i)) 53 if totalCoins.Cmp(CalculateNumSiacoins(i)) != 0 { 54 t.Fatal("coin miscalculation", i, totalCoins, CalculateNumSiacoins(i)) 55 } 56 } 57 } 58 59 // TestBlockHeader checks that BlockHeader returns the correct value, and that 60 // the hash is consistent with the old method for obtaining the hash. 61 func TestBlockHeader(t *testing.T) { 62 var b Block 63 b.ParentID[1] = 1 64 b.Nonce[2] = 2 65 b.Timestamp = 3 66 b.MinerPayouts = []SiacoinOutput{{Value: NewCurrency64(4)}} 67 b.Transactions = []Transaction{{ArbitraryData: [][]byte{{'5'}}}} 68 69 id1 := b.ID() 70 id2 := BlockID(crypto.HashBytes(encoding.Marshal(b.Header()))) 71 id3 := BlockID(crypto.HashAll( 72 b.ParentID, 73 b.Nonce, 74 b.Timestamp, 75 b.MerkleRoot(), 76 )) 77 78 if id1 != id2 || id2 != id3 || id3 != id1 { 79 t.Error("Methods for getting block id don't return the same results") 80 } 81 } 82 83 // TestBlockID probes the ID function of the block type. 84 func TestBlockID(t *testing.T) { 85 // Create a bunch of different blocks and check that all of them have 86 // unique ids. 87 var b Block 88 var ids []BlockID 89 90 ids = append(ids, b.ID()) 91 b.ParentID[0] = 1 92 ids = append(ids, b.ID()) 93 b.Nonce[0] = 45 94 ids = append(ids, b.ID()) 95 b.Timestamp = CurrentTimestamp() 96 ids = append(ids, b.ID()) 97 b.MinerPayouts = append(b.MinerPayouts, SiacoinOutput{Value: CalculateCoinbase(0)}) 98 ids = append(ids, b.ID()) 99 b.MinerPayouts = append(b.MinerPayouts, SiacoinOutput{Value: CalculateCoinbase(0)}) 100 ids = append(ids, b.ID()) 101 b.Transactions = append(b.Transactions, Transaction{MinerFees: []Currency{CalculateCoinbase(1)}}) 102 ids = append(ids, b.ID()) 103 b.Transactions = append(b.Transactions, Transaction{MinerFees: []Currency{CalculateCoinbase(1)}}) 104 ids = append(ids, b.ID()) 105 106 knownIDs := make(map[BlockID]struct{}) 107 for i, id := range ids { 108 _, exists := knownIDs[id] 109 if exists { 110 t.Error("id repeat for index", i) 111 } 112 knownIDs[id] = struct{}{} 113 } 114 } 115 116 // TestHeaderID probes the ID function of the BlockHeader type. 117 func TestHeaderID(t *testing.T) { 118 // Create a bunch of different blocks and check that all of them have 119 // unique ids. 120 var blocks []Block 121 var b Block 122 123 blocks = append(blocks, b) 124 b.ParentID[0] = 1 125 blocks = append(blocks, b) 126 b.Nonce[0] = 45 127 blocks = append(blocks, b) 128 b.Timestamp = CurrentTimestamp() 129 blocks = append(blocks, b) 130 b.MinerPayouts = append(b.MinerPayouts, SiacoinOutput{Value: CalculateCoinbase(0)}) 131 blocks = append(blocks, b) 132 b.MinerPayouts = append(b.MinerPayouts, SiacoinOutput{Value: CalculateCoinbase(0)}) 133 blocks = append(blocks, b) 134 b.Transactions = append(b.Transactions, Transaction{MinerFees: []Currency{CalculateCoinbase(1)}}) 135 blocks = append(blocks, b) 136 b.Transactions = append(b.Transactions, Transaction{MinerFees: []Currency{CalculateCoinbase(1)}}) 137 blocks = append(blocks, b) 138 139 knownIDs := make(map[BlockID]struct{}) 140 for i, block := range blocks { 141 blockID := block.ID() 142 headerID := block.Header().ID() 143 if blockID != headerID { 144 t.Error("headerID does not match blockID for index", i) 145 } 146 _, exists := knownIDs[headerID] 147 if exists { 148 t.Error("id repeat for index", i) 149 } 150 knownIDs[headerID] = struct{}{} 151 } 152 } 153 154 // TestBlockCalculateSubsidy probes the CalculateSubsidy function of the block 155 // type. 156 func TestBlockCalculateSubsidy(t *testing.T) { 157 // All tests are done at height = 0. 158 coinbase := CalculateCoinbase(0) 159 160 // Calculate the subsidy on a block with 0 fees at height 0. Result should 161 // be 300,000. 162 var b Block 163 if b.CalculateSubsidy(0).Cmp(coinbase) != 0 { 164 t.Error("subsidy is miscalculated for an empty block") 165 } 166 167 // Calculate when there is a fee in a transcation. 168 expected := coinbase.Add(NewCurrency64(123)) 169 txn := Transaction{ 170 MinerFees: []Currency{NewCurrency64(123)}, 171 } 172 b.Transactions = append(b.Transactions, txn) 173 if b.CalculateSubsidy(0).Cmp(expected) != 0 { 174 t.Error("subsidy is miscalculated for a block with a single transaction") 175 } 176 177 // Add a single no-fee transaction and check again. 178 txn = Transaction{ 179 ArbitraryData: [][]byte{{'6'}}, 180 } 181 b.Transactions = append(b.Transactions, txn) 182 if b.CalculateSubsidy(0).Cmp(expected) != 0 { 183 t.Error("subsidy is miscalculated with empty transactions.") 184 } 185 186 // Add a transaction with multiple fees. 187 expected = expected.Add(NewCurrency64(1 + 2 + 3)) 188 txn = Transaction{ 189 MinerFees: []Currency{ 190 NewCurrency64(1), 191 NewCurrency64(2), 192 NewCurrency64(3), 193 }, 194 } 195 b.Transactions = append(b.Transactions, txn) 196 if b.CalculateSubsidy(0).Cmp(expected) != 0 { 197 t.Error("subsidy is miscalculated for a block with a single transaction") 198 } 199 200 // Add an empty transaction to the beginning. 201 txn = Transaction{ 202 ArbitraryData: [][]byte{{'7'}}, 203 } 204 b.Transactions = append([]Transaction{txn}, b.Transactions...) 205 if b.CalculateSubsidy(0).Cmp(expected) != 0 { 206 t.Error("subsidy is miscalculated with empty transactions.") 207 } 208 } 209 210 // TestBlockMinerPayoutID probes the MinerPayout function of the block type. 211 func TestBlockMinerPayoutID(t *testing.T) { 212 // Create a block with 2 miner payouts, and check that each payout has a 213 // different id, and that the id is dependent on the block id. 214 var ids []SiacoinOutputID 215 b := Block{ 216 MinerPayouts: []SiacoinOutput{ 217 {Value: CalculateCoinbase(0)}, 218 {Value: CalculateCoinbase(0)}, 219 }, 220 } 221 ids = append(ids, b.MinerPayoutID(1), b.MinerPayoutID(2)) 222 b.ParentID[0] = 1 223 ids = append(ids, b.MinerPayoutID(1), b.MinerPayoutID(2)) 224 225 knownIDs := make(map[SiacoinOutputID]struct{}) 226 for i, id := range ids { 227 _, exists := knownIDs[id] 228 if exists { 229 t.Error("id repeat for index", i) 230 } 231 knownIDs[id] = struct{}{} 232 } 233 } 234 235 // TestBlockEncodes probes the MarshalSia and UnmarshalSia methods of the 236 // Block type. 237 func TestBlockEncoding(t *testing.T) { 238 b := Block{ 239 MinerPayouts: []SiacoinOutput{ 240 {Value: CalculateCoinbase(0)}, 241 {Value: CalculateCoinbase(0)}, 242 }, 243 } 244 var decB Block 245 err := encoding.Unmarshal(encoding.Marshal(b), &decB) 246 if err != nil { 247 t.Fatal(err) 248 } 249 if len(decB.MinerPayouts) != len(b.MinerPayouts) || 250 decB.MinerPayouts[0].Value.Cmp(b.MinerPayouts[0].Value) != 0 || 251 decB.MinerPayouts[1].Value.Cmp(b.MinerPayouts[1].Value) != 0 { 252 t.Fatal("block changed after encode/decode:", b, decB) 253 } 254 }