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