github.com/fozzysec/SiaPrime@v0.0.0-20190612043147-66c8e8d11fe3/types/encoding_test.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "math/big" 8 "strings" 9 "testing" 10 11 "SiaPrime/crypto" 12 "SiaPrime/encoding" 13 "gitlab.com/NebulousLabs/fastrand" 14 ) 15 16 func hashStr(v interface{}) string { 17 h := crypto.HashObject(v) 18 return fmt.Sprintf("%x", h[:]) 19 } 20 21 // heavyBlock is a complex block that fills every possible field with data. 22 var heavyBlock = func() Block { 23 b := Block{ 24 MinerPayouts: []SiacoinOutput{ 25 {Value: CalculateCoinbase(0)}, 26 {Value: CalculateCoinbase(1)}, 27 }, 28 Transactions: []Transaction{ 29 { 30 SiacoinInputs: []SiacoinInput{{ 31 UnlockConditions: UnlockConditions{ 32 PublicKeys: []SiaPublicKey{{ 33 Algorithm: SignatureEd25519, 34 Key: fastrand.Bytes(32), 35 }}, 36 SignaturesRequired: 6, 37 }, 38 }}, 39 SiacoinOutputs: []SiacoinOutput{{ 40 Value: NewCurrency64(20), 41 }}, 42 FileContracts: []FileContract{{ 43 FileSize: 12, 44 Payout: NewCurrency64(100), 45 RevisionNumber: 8, 46 ValidProofOutputs: []SiacoinOutput{{ 47 Value: NewCurrency64(2), 48 }}, 49 MissedProofOutputs: []SiacoinOutput{{ 50 Value: NewCurrency64(3), 51 }}, 52 }}, 53 FileContractRevisions: []FileContractRevision{{ 54 NewFileSize: 13, 55 NewRevisionNumber: 9, 56 UnlockConditions: UnlockConditions{ 57 PublicKeys: []SiaPublicKey{{ 58 Algorithm: SignatureEd25519, 59 Key: fastrand.Bytes(32), 60 }}, 61 }, 62 NewValidProofOutputs: []SiacoinOutput{{ 63 Value: NewCurrency64(4), 64 }}, 65 NewMissedProofOutputs: []SiacoinOutput{{ 66 Value: NewCurrency64(5), 67 }}, 68 }}, 69 StorageProofs: []StorageProof{{ 70 HashSet: []crypto.Hash{{}}, 71 }}, 72 SiafundInputs: []SiafundInput{{ 73 UnlockConditions: UnlockConditions{ 74 PublicKeys: []SiaPublicKey{{ 75 Algorithm: SignatureEd25519, 76 Key: fastrand.Bytes(32), 77 }}, 78 }, 79 }}, 80 SiafundOutputs: []SiafundOutput{{ 81 ClaimStart: NewCurrency64(99), 82 Value: NewCurrency64(25), 83 }}, 84 MinerFees: []Currency{NewCurrency64(215)}, 85 ArbitraryData: [][]byte{fastrand.Bytes(10)}, 86 TransactionSignatures: []TransactionSignature{{ 87 PublicKeyIndex: 5, 88 Timelock: 80, 89 CoveredFields: CoveredFields{ 90 WholeTransaction: true, 91 SiacoinInputs: []uint64{0}, 92 SiacoinOutputs: []uint64{1}, 93 FileContracts: []uint64{2}, 94 FileContractRevisions: []uint64{3}, 95 StorageProofs: []uint64{4}, 96 SiafundInputs: []uint64{5}, 97 SiafundOutputs: []uint64{6}, 98 MinerFees: []uint64{7}, 99 ArbitraryData: []uint64{8}, 100 TransactionSignatures: []uint64{9}, 101 }, 102 Signature: fastrand.Bytes(32), 103 }}, 104 }, 105 }, 106 } 107 fastrand.Read(b.Transactions[0].SiacoinInputs[0].ParentID[:]) 108 fastrand.Read(b.Transactions[0].SiacoinOutputs[0].UnlockHash[:]) 109 fastrand.Read(b.Transactions[0].FileContracts[0].FileMerkleRoot[:]) 110 fastrand.Read(b.Transactions[0].FileContracts[0].ValidProofOutputs[0].UnlockHash[:]) 111 fastrand.Read(b.Transactions[0].FileContracts[0].MissedProofOutputs[0].UnlockHash[:]) 112 fastrand.Read(b.Transactions[0].FileContractRevisions[0].ParentID[:]) 113 fastrand.Read(b.Transactions[0].FileContractRevisions[0].NewFileMerkleRoot[:]) 114 fastrand.Read(b.Transactions[0].FileContractRevisions[0].NewValidProofOutputs[0].UnlockHash[:]) 115 fastrand.Read(b.Transactions[0].FileContractRevisions[0].NewMissedProofOutputs[0].UnlockHash[:]) 116 fastrand.Read(b.Transactions[0].StorageProofs[0].ParentID[:]) 117 fastrand.Read(b.Transactions[0].StorageProofs[0].HashSet[0][:]) 118 fastrand.Read(b.Transactions[0].StorageProofs[0].Segment[:]) 119 fastrand.Read(b.Transactions[0].SiafundInputs[0].ParentID[:]) 120 fastrand.Read(b.Transactions[0].SiafundInputs[0].ClaimUnlockHash[:]) 121 fastrand.Read(b.Transactions[0].SiafundOutputs[0].UnlockHash[:]) 122 fastrand.Read(b.Transactions[0].TransactionSignatures[0].ParentID[:]) 123 return b 124 }() 125 126 // TestBlockEncodes probes the MarshalSia and UnmarshalSia methods of the 127 // Block type. 128 func TestBlockEncoding(t *testing.T) { 129 var decB Block 130 err := encoding.Unmarshal(encoding.Marshal(heavyBlock), &decB) 131 if err != nil { 132 t.Fatal(err) 133 } 134 if hashStr(heavyBlock) != hashStr(decB) { 135 t.Fatal("block changed after encode/decode:", heavyBlock, decB) 136 } 137 } 138 139 // TestBadBlock tests that a known invalid encoding is not successfully 140 // decoded. 141 func TestBadBlock(t *testing.T) { 142 badData := "000000000000000000000000000000000000000000000000\x00\x00\x00\x00\x00\x00\x00\x00\x00" 143 var block Block 144 err := encoding.Unmarshal([]byte(badData), &block) 145 if err == nil { 146 t.Fatal("invalid block decoded successfully") 147 } 148 } 149 150 // TestTooLargeDecoder tests that the decoder catches allocations that are too 151 // large. 152 func TestTooLargeDecoder(t *testing.T) { 153 if testing.Short() { 154 t.SkipNow() 155 } 156 enc := encoding.Marshal(Block{}) 157 // change number of transactions to large number 158 copy(enc[len(enc)-8:], encoding.EncUint64(^uint64(0))) 159 var block Block 160 err := encoding.Unmarshal(enc, &block) 161 if err == nil { 162 t.Fatal("expected error, got nil") 163 } 164 165 var arb [][]byte 166 for i := 0; i < 4; i++ { 167 arb = append(arb, make([]byte, encoding.MaxSliceSize-1)) 168 } 169 block.Transactions = []Transaction{{ 170 ArbitraryData: arb, 171 }} 172 enc = encoding.Marshal(block) 173 err = encoding.Unmarshal(enc, &block) 174 if err == nil { 175 t.Fatal("expected error, got nil") 176 } 177 } 178 179 // TestCurrencyMarshalJSON probes the MarshalJSON and UnmarshalJSON functions 180 // of the currency type. 181 func TestCurrencyMarshalJSON(t *testing.T) { 182 b30 := big.NewInt(30) 183 c30 := NewCurrency64(30) 184 185 bMar30, err := b30.MarshalJSON() 186 if err != nil { 187 t.Fatal(err) 188 } 189 cMar30, err := c30.MarshalJSON() 190 if err != nil { 191 t.Fatal(err) 192 } 193 if !bytes.Equal(bMar30, bytes.Trim(cMar30, `"`)) { 194 t.Error("Currency does not match the marshalling of its math/big equivalent") 195 } 196 197 var cUmar30 Currency 198 err = cUmar30.UnmarshalJSON(cMar30) 199 if err != nil { 200 t.Fatal(err) 201 } 202 if c30.Cmp(cUmar30) != 0 { 203 t.Error("Incorrect unmarshalling of currency type.") 204 } 205 206 cMar30[0] = 0 207 err = cUmar30.UnmarshalJSON(cMar30) 208 if err == nil { 209 t.Error("JSON decoded nonsense input") 210 } 211 } 212 213 // TestCurrencyMarshalSia probes the MarshalSia and UnmarshalSia functions of 214 // the currency type. 215 func TestCurrencyMarshalSia(t *testing.T) { 216 c := NewCurrency64(1656) 217 buf := new(bytes.Buffer) 218 err := c.MarshalSia(buf) 219 if err != nil { 220 t.Fatal(err) 221 } 222 var cUmar Currency 223 cUmar.UnmarshalSia(buf) 224 if c.Cmp(cUmar) != 0 { 225 t.Error("marshal and unmarshal mismatch for currency type") 226 } 227 } 228 229 // TestCurrencyString probes the String function of the currency type. 230 func TestCurrencyString(t *testing.T) { 231 b := big.NewInt(7135) 232 c := NewCurrency64(7135) 233 if b.String() != c.String() { 234 t.Error("string function not behaving as expected") 235 } 236 } 237 238 // TestCurrencyScan probes the Scan function of the currency type. 239 func TestCurrencyScan(t *testing.T) { 240 var c0 Currency 241 c1 := NewCurrency64(81293) 242 _, err := fmt.Sscan("81293", &c0) 243 if err != nil { 244 t.Fatal(err) 245 } 246 if c0.Cmp(c1) != 0 { 247 t.Error("scanned number does not equal expected value") 248 } 249 _, err = fmt.Sscan("z", &c0) 250 if err == nil { 251 t.Fatal("scan is accepting garbage input") 252 } 253 } 254 255 // TestCurrencyEncoding checks that a currency can encode and decode without 256 // error. 257 func TestCurrencyEncoding(t *testing.T) { 258 c := NewCurrency64(351) 259 cMar := encoding.Marshal(c) 260 var cUmar Currency 261 err := encoding.Unmarshal(cMar, &cUmar) 262 if err != nil { 263 t.Error("Error unmarshalling a currency:", err) 264 } 265 if cUmar.Cmp(c) != 0 { 266 t.Error("Marshalling and Unmarshalling a currency did not work correctly") 267 } 268 } 269 270 // TestNegativeCurrencyUnmarshalJSON tries to unmarshal a negative number from 271 // JSON. 272 func TestNegativeCurrencyUnmarshalJSON(t *testing.T) { 273 // Marshal a 2 digit number. 274 c := NewCurrency64(35) 275 cMar, err := c.MarshalJSON() 276 if err != nil { 277 t.Fatal(err) 278 } 279 280 // Change the first digit to a negative character. 281 cMar[0] = 45 282 283 // Try unmarshalling the negative currency. 284 var cNeg Currency 285 err = cNeg.UnmarshalJSON(cMar) 286 if err != ErrNegativeCurrency { 287 t.Error("expecting ErrNegativeCurrency:", err) 288 } 289 if cNeg.i.Sign() < 0 { 290 t.Error("negative currency returned") 291 } 292 } 293 294 // TestNegativeCurrencyScan tries to scan in a negative number and checks for 295 // an error. 296 func TestNegativeCurrencyScan(t *testing.T) { 297 var c Currency 298 _, err := fmt.Sscan("-23", &c) 299 if err != ErrNegativeCurrency { 300 t.Error("expecting ErrNegativeCurrency:", err) 301 } 302 } 303 304 // TestCurrencyUnsafeDecode tests that decoding into an existing Currency 305 // value does not overwrite its contents. 306 func TestCurrencyUnsafeDecode(t *testing.T) { 307 // Scan 308 backup := SiacoinPrecision.Mul64(1) 309 c := SiacoinPrecision 310 _, err := fmt.Sscan("7", &c) 311 if err != nil { 312 t.Error(err) 313 } else if !SiacoinPrecision.Equals(backup) { 314 t.Errorf("Scan changed value of SiacoinPrecision: %v -> %v", backup, SiacoinPrecision) 315 } 316 317 // UnmarshalSia 318 c = SiacoinPrecision 319 err = encoding.Unmarshal(encoding.Marshal(NewCurrency64(7)), &c) 320 if err != nil { 321 t.Error(err) 322 } else if !SiacoinPrecision.Equals(backup) { 323 t.Errorf("UnmarshalSia changed value of SiacoinPrecision: %v -> %v", backup, SiacoinPrecision) 324 } 325 } 326 327 // TestTransactionEncoding tests that optimizations applied to the encoding of 328 // the Transaction type do not change its encoding. 329 func TestTransactionEncoding(t *testing.T) { 330 var txn Transaction 331 if h := hashStr(txn); h != "143aa0da2b6a4ca39eee3ee50a6536d75eedff3b5ef0229a6d603afa7854d5b8" { 332 t.Error("encoding mismatch:", h) 333 } 334 335 txn = Transaction{ 336 SiacoinInputs: []SiacoinInput{{}}, 337 SiacoinOutputs: []SiacoinOutput{{}}, 338 FileContracts: []FileContract{{}}, 339 FileContractRevisions: []FileContractRevision{{}}, 340 StorageProofs: []StorageProof{{}}, 341 SiafundInputs: []SiafundInput{{}}, 342 SiafundOutputs: []SiafundOutput{{}}, 343 MinerFees: []Currency{{}}, 344 ArbitraryData: [][]byte{{}}, 345 TransactionSignatures: []TransactionSignature{{}}, 346 } 347 if h := hashStr(txn); h != "a6c0f41cb89aaede0682ab06c1e757e12d662a0156ec878f85b935bc219fb3ca" { 348 t.Error("encoding mismatch:", h) 349 } 350 } 351 352 // TestSiacoinInputEncoding tests that optimizations applied to the encoding 353 // of the SiacoinInput type do not change its encoding. 354 func TestSiacoinInputEncoding(t *testing.T) { 355 var sci SiacoinInput 356 if h := hashStr(sci); h != "2f806f905436dc7c5079ad8062467266e225d8110a3c58d17628d609cb1c99d0" { 357 t.Error("encoding mismatch:", h) 358 } 359 360 sci = SiacoinInput{ 361 ParentID: SiacoinOutputID{1, 2, 3}, 362 UnlockConditions: UnlockConditions{}, 363 } 364 if h := hashStr(sci); h != "f172a8f5892bb2b63eff32de6fd83c132be5ad134d1227d8881632bd809ae075" { 365 t.Error("encoding mismatch:", h) 366 } 367 } 368 369 // TestSiacoinOutputEncoding tests that optimizations applied to the encoding 370 // of the SiacoinOutput type do not change its encoding. 371 func TestSiacoinOutputEncoding(t *testing.T) { 372 var sco SiacoinOutput 373 if h := hashStr(sco); h != "4a1931803561f431decab002e7425f0a8531d5e456a1a47fd9998a2530c0f800" { 374 t.Error("encoding mismatch:", h) 375 } 376 377 sco = SiacoinOutput{ 378 Value: NewCurrency64(0), 379 UnlockHash: UnlockHash{1, 2, 3}, 380 } 381 if h := hashStr(sco); h != "32fb94ae64201f3e0a373947382367666bcf205d47a58ece9260c459986ae6fd" { 382 t.Error("encoding mismatch:", h) 383 } 384 } 385 386 // TestSiafundInputEncoding tests that optimizations applied to the encoding 387 // of the SiafundInput type do not change its encoding. 388 func TestSiafundInputEncoding(t *testing.T) { 389 var sci SiafundInput 390 if h := hashStr(sci); h != "978a948b1a92bcddcea382bafc7718a25f8cc49b8fb11db5d9159afa960cf70a" { 391 t.Error("encoding mismatch:", h) 392 } 393 394 sci = SiafundInput{ 395 ParentID: SiafundOutputID{1, 2, 3}, 396 UnlockConditions: UnlockConditions{1, nil, 3}, 397 ClaimUnlockHash: UnlockHash{1, 2, 3}, 398 } 399 if h := hashStr(sci); h != "1a6781ca002262e1def98e294f86dd81f866e2db9029954c64a36d20d0c6b46f" { 400 t.Error("encoding mismatch:", h) 401 } 402 } 403 404 // TestSiafundOutputEncoding tests that optimizations applied to the encoding 405 // of the SiafundOutput type do not change its encoding. 406 func TestSiafundOutputEncoding(t *testing.T) { 407 var sco SiafundOutput 408 if h := hashStr(sco); h != "df69a516de12056d0895fdea7a0274c5aba67091543238670513104c1af69c1f" { 409 t.Error("encoding mismatch:", h) 410 } 411 412 sco = SiafundOutput{ 413 Value: NewCurrency64(0), 414 UnlockHash: UnlockHash{1, 2, 3}, 415 ClaimStart: NewCurrency64(4), 416 } 417 if h := hashStr(sco); h != "9524d2250b21adc76967e9f86d26a68982727329e5c42a6bf5e62504891a5176" { 418 t.Error("encoding mismatch:", h) 419 } 420 } 421 422 // TestCoveredFieldsEncoding tests that optimizations applied to the encoding 423 // of the CoveredFields type do not change its encoding. 424 func TestCoveredFieldsEncoding(t *testing.T) { 425 var cf CoveredFields 426 if h := hashStr(cf); h != "aecfdceb8b630b5b00668d229221f876b3be1630703c4615a642db2c666b4fd7" { 427 t.Error("encoding mismatch:", h) 428 } 429 430 cf = CoveredFields{ 431 WholeTransaction: true, 432 SiacoinInputs: []uint64{0}, 433 SiacoinOutputs: []uint64{1}, 434 FileContracts: []uint64{2}, 435 FileContractRevisions: []uint64{3}, 436 StorageProofs: []uint64{4}, 437 SiafundInputs: []uint64{5}, 438 SiafundOutputs: []uint64{6}, 439 MinerFees: []uint64{7}, 440 ArbitraryData: []uint64{8}, 441 TransactionSignatures: []uint64{9, 10}, 442 } 443 if h := hashStr(cf); h != "5b10cd6b50b09447aae02829643e62b513ce99b969a80aeb620f74e77ca9bbba" { 444 t.Error("encoding mismatch:", h) 445 } 446 } 447 448 // TestSiaPublicKeyEncoding tests that optimizations applied to the encoding 449 // of the SiaPublicKey type do not change its encoding. 450 func TestSiaPublicKeyEncoding(t *testing.T) { 451 var spk SiaPublicKey 452 if h := hashStr(spk); h != "19ea4a516c66775ea1f648d71f6b8fa227e8b0c1a0c9203f82c33b89c4e759b5" { 453 t.Error("encoding mismatch:", h) 454 } 455 456 spk = SiaPublicKey{ 457 Algorithm: Specifier{1, 2, 3}, 458 Key: []byte{4, 5, 6}, 459 } 460 if h := hashStr(spk); h != "9c781bbeebc23a1885d00e778c358f0a4bc81a82b48191449129752a380adc03" { 461 t.Error("encoding mismatch:", h) 462 } 463 } 464 465 // TestSiaPublicKeyLoadString checks that the LoadString method is the proper 466 // inverse of the String() method, also checks that there are no stupid panics 467 // or severe errors. 468 func TestSiaPublicKeyLoadString(t *testing.T) { 469 spk := SiaPublicKey{ 470 Algorithm: SignatureEd25519, 471 Key: fastrand.Bytes(32), 472 } 473 474 spkString := spk.String() 475 var loadedSPK SiaPublicKey 476 loadedSPK.LoadString(spkString) 477 if !bytes.Equal(loadedSPK.Algorithm[:], spk.Algorithm[:]) { 478 t.Error("SiaPublicKey is not loading correctly") 479 } 480 if !bytes.Equal(loadedSPK.Key, spk.Key) { 481 t.Log(loadedSPK.Key, spk.Key) 482 t.Error("SiaPublicKey is not loading correctly") 483 } 484 485 // Try loading crappy strings. 486 parts := strings.Split(spkString, ":") 487 spk.LoadString(parts[0]) 488 spk.LoadString(parts[0][1:]) 489 spk.LoadString(parts[0][:1]) 490 spk.LoadString(parts[1]) 491 spk.LoadString(parts[1][1:]) 492 spk.LoadString(parts[1][:1]) 493 spk.LoadString(parts[0] + parts[1]) 494 495 } 496 497 // TestSiaPublicKeyString does a quick check to verify that the String method 498 // on the SiaPublicKey is producing the expected output. 499 func TestSiaPublicKeyString(t *testing.T) { 500 spk := SiaPublicKey{ 501 Algorithm: SignatureEd25519, 502 Key: make([]byte, 32), 503 } 504 505 if spk.String() != "ed25519:0000000000000000000000000000000000000000000000000000000000000000" { 506 t.Error("got wrong value for spk.String():", spk.String()) 507 } 508 } 509 510 // TestSiaPublicKeyUnmarshalJSON checks that UnmarshalJSON supports both 511 // encodings of SiaPublicKey. 512 func TestSiaPublicKeyUnmarshalJSON(t *testing.T) { 513 js1 := `{ "algorithm": "ed25519", "key": "5GhilFqVBKtSCedCZc6TIthzxvyBH9gPqqf+Z9hsfBo=" }` 514 var spk1 SiaPublicKey 515 if err := json.Unmarshal([]byte(js1), &spk1); err != nil { 516 t.Error(err) 517 } 518 519 js2 := `"ed25519:e46862945a9504ab5209e74265ce9322d873c6fc811fd80faaa7fe67d86c7c1a"` 520 var spk2 SiaPublicKey 521 var _ json.Unmarshaler = &spk2 522 if err := json.Unmarshal([]byte(js2), &spk2); err != nil { 523 t.Fatal(err) 524 } 525 526 if spk1.Algorithm != spk2.Algorithm { 527 t.Error("unmarshalled algorithms do not match") 528 } 529 if !bytes.Equal(spk1.Key, spk2.Key) { 530 t.Error("unmarshalled keys do not match") 531 } 532 } 533 534 // TestSpecifierMarshaling tests the marshaling methods of the specifier 535 // type. 536 func TestSpecifierMarshaling(t *testing.T) { 537 s1 := SpecifierClaimOutput 538 b, err := json.Marshal(s1) 539 if err != nil { 540 t.Fatal(err) 541 } 542 var s2 Specifier 543 err = json.Unmarshal(b, &s2) 544 if err != nil { 545 t.Fatal(err) 546 } else if s2 != s1 { 547 t.Fatal("mismatch:", s1, s2) 548 } 549 550 // invalid json 551 x := 3 552 b, _ = json.Marshal(x) 553 err = json.Unmarshal(b, &s2) 554 if err == nil { 555 t.Fatal("Unmarshal should have failed") 556 } 557 } 558 559 // TestTransactionSignatureEncoding tests that optimizations applied to the 560 // encoding of the TransactionSignature type do not change its encoding. 561 func TestTransactionSignatureEncoding(t *testing.T) { 562 var ts TransactionSignature 563 if h := hashStr(ts); h != "5801097b0ae98fe7cedd4569afc11c0a433f284681ad4d66dd7181293f6d2bba" { 564 t.Error("encoding mismatch:", h) 565 } 566 567 ts = TransactionSignature{ 568 ParentID: crypto.Hash{1, 2, 3}, 569 PublicKeyIndex: 4, 570 Timelock: 5, 571 CoveredFields: CoveredFields{}, 572 Signature: []byte{6, 7, 8}, 573 } 574 if h := hashStr(ts); h != "a3ce36fd8e1d6b7e5b030cdc2630d24a44472072bbd06e94d32d11132d817db0" { 575 t.Error("encoding mismatch:", h) 576 } 577 } 578 579 // TestUnlockConditionsEncoding tests that optimizations applied to the 580 // encoding of the UnlockConditions type do not change its encoding. 581 func TestUnlockConditionsEncoding(t *testing.T) { 582 var uc UnlockConditions 583 if h := hashStr(uc); h != "19ea4a516c66775ea1f648d71f6b8fa227e8b0c1a0c9203f82c33b89c4e759b5" { 584 t.Error("encoding mismatch:", h) 585 } 586 587 uc = UnlockConditions{ 588 Timelock: 1, 589 PublicKeys: []SiaPublicKey{{}}, 590 SignaturesRequired: 3, 591 } 592 if h := hashStr(uc); h != "164d3741bd274d5333ab1fe8ab641b9d25cb0e0bed8e1d7bc466b5fffc956d96" { 593 t.Error("encoding mismatch:", h) 594 } 595 } 596 597 // TestUnlockHashJSONMarshalling checks that when an unlock hash is marshalled 598 // and unmarshalled using JSON, the result is what is expected. 599 func TestUnlockHashJSONMarshalling(t *testing.T) { 600 // Create an unlock hash. 601 uc := UnlockConditions{ 602 Timelock: 5, 603 SignaturesRequired: 3, 604 } 605 uh := uc.UnlockHash() 606 607 // Marshal the unlock hash. 608 marUH, err := json.Marshal(uh) 609 if err != nil { 610 t.Fatal(err) 611 } 612 613 // Unmarshal the unlock hash and compare to the original. 614 var umarUH UnlockHash 615 err = json.Unmarshal(marUH, &umarUH) 616 if err != nil { 617 t.Fatal(err) 618 } 619 if umarUH != uh { 620 t.Error("Marshalled and unmarshalled unlock hash are not equivalent") 621 } 622 623 // Corrupt the checksum. 624 marUH[36]++ 625 err = umarUH.UnmarshalJSON(marUH) 626 if err != ErrInvalidUnlockHashChecksum { 627 t.Error("expecting an invalid checksum:", err) 628 } 629 marUH[36]-- 630 631 // Try an input that's not correct hex. 632 marUH[7] += 100 633 err = umarUH.UnmarshalJSON(marUH) 634 if err == nil { 635 t.Error("Expecting error after corrupting input") 636 } 637 marUH[7] -= 100 638 639 // Try an input of the wrong length. 640 err = (&umarUH).UnmarshalJSON(marUH[2:]) 641 if err != ErrUnlockHashWrongLen { 642 t.Error("Got wrong error:", err) 643 } 644 } 645 646 // TestUnlockHashStringMarshalling checks that when an unlock hash is 647 // marshalled and unmarshalled using String and LoadString, the result is what 648 // is expected. 649 func TestUnlockHashStringMarshalling(t *testing.T) { 650 // Create an unlock hash. 651 uc := UnlockConditions{ 652 Timelock: 2, 653 SignaturesRequired: 7, 654 } 655 uh := uc.UnlockHash() 656 657 // Marshal the unlock hash. 658 marUH := uh.String() 659 660 // Unmarshal the unlock hash and compare to the original. 661 var umarUH UnlockHash 662 err := umarUH.LoadString(marUH) 663 if err != nil { 664 t.Fatal(err) 665 } 666 if umarUH != uh { 667 t.Error("Marshalled and unmarshalled unlock hash are not equivalent") 668 } 669 670 // Corrupt the checksum. 671 byteMarUH := []byte(marUH) 672 byteMarUH[36]++ 673 err = umarUH.LoadString(string(byteMarUH)) 674 if err != ErrInvalidUnlockHashChecksum { 675 t.Error("expecting an invalid checksum:", err) 676 } 677 byteMarUH[36]-- 678 679 // Try an input that's not correct hex. 680 byteMarUH[7] += 100 681 err = umarUH.LoadString(string(byteMarUH)) 682 if err == nil { 683 t.Error("Expecting error after corrupting input") 684 } 685 byteMarUH[7] -= 100 686 687 // Try an input of the wrong length. 688 err = umarUH.LoadString(string(byteMarUH[2:])) 689 if err != ErrUnlockHashWrongLen { 690 t.Error("Got wrong error:", err) 691 } 692 } 693 694 // TestCurrencyHumanString checks that the HumanString method of the currency 695 // type is correctly formatting values. 696 func TestCurrencyUnits(t *testing.T) { 697 tests := []struct { 698 in Currency 699 out string 700 }{ 701 {NewCurrency64(1), "1 H"}, 702 {NewCurrency64(1000), "1000 H"}, 703 {NewCurrency64(100000000000), "100000000000 H"}, 704 {NewCurrency64(1000000000000), "1 pS"}, 705 {NewCurrency64(1234560000000), "1.235 pS"}, 706 {NewCurrency64(12345600000000), "12.35 pS"}, 707 {NewCurrency64(123456000000000), "123.5 pS"}, 708 {NewCurrency64(1000000000000000), "1 nS"}, 709 {NewCurrency64(1000000000000000000), "1 uS"}, 710 {NewCurrency64(1000000000).Mul64(1000000000000), "1 mS"}, 711 {NewCurrency64(1).Mul(SiacoinPrecision), "1 SC"}, 712 {NewCurrency64(1000).Mul(SiacoinPrecision), "1 KS"}, 713 {NewCurrency64(1000000).Mul(SiacoinPrecision), "1 MS"}, 714 {NewCurrency64(1000000000).Mul(SiacoinPrecision), "1 GS"}, 715 {NewCurrency64(1000000000000).Mul(SiacoinPrecision), "1 TS"}, 716 {NewCurrency64(1234560000000).Mul(SiacoinPrecision), "1.235 TS"}, 717 {NewCurrency64(1234560000000000).Mul(SiacoinPrecision), "1235 TS"}, 718 } 719 for _, test := range tests { 720 if test.in.HumanString() != test.out { 721 t.Errorf("currencyUnits(%v): expected %v, got %v", test.in, test.out, test.in.HumanString()) 722 } 723 } 724 } 725 726 // TestTransactionMarshalSiaSize tests that the txn.MarshalSiaSize method is 727 // always consistent with len(encoding.Marshal(txn)). 728 func TestTransactionMarshalSiaSize(t *testing.T) { 729 txn := Transaction{ 730 SiacoinInputs: []SiacoinInput{{}}, 731 SiacoinOutputs: []SiacoinOutput{{}}, 732 FileContracts: []FileContract{{}}, 733 FileContractRevisions: []FileContractRevision{{}}, 734 StorageProofs: []StorageProof{{}}, 735 SiafundInputs: []SiafundInput{{}}, 736 SiafundOutputs: []SiafundOutput{{}}, 737 MinerFees: []Currency{{}}, 738 ArbitraryData: [][]byte{{}}, 739 TransactionSignatures: []TransactionSignature{{}}, 740 } 741 if txn.MarshalSiaSize() != len(encoding.Marshal(txn)) { 742 t.Errorf("sizes do not match: expected %v, got %v", len(encoding.Marshal(txn)), txn.MarshalSiaSize()) 743 } 744 } 745 746 // TestUnlockHashScan checks if the fmt.Scanner implementation of UnlockHash 747 // works as expected. 748 func TestUnlockHashScan(t *testing.T) { 749 // Create a random unlock hash. 750 var uh UnlockHash 751 fastrand.Read(uh[:]) 752 // Convert it to a string and parse the string using Sscan. 753 var scannedHash UnlockHash 754 fmt.Sscan(uh.String(), &scannedHash) 755 // Check if they are equal. 756 if !bytes.Equal(uh[:], scannedHash[:]) { 757 t.Fatal("scanned hash is not equal to original hash") 758 } 759 }