github.com/dmmcquay/sia@v1.3.1-0.20180712220038-9f8d535311b9/types/encoding.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "encoding/json" 7 "fmt" 8 "io" 9 "math/big" 10 "strings" 11 "unsafe" 12 13 "github.com/NebulousLabs/Sia/build" 14 "github.com/NebulousLabs/Sia/crypto" 15 "github.com/NebulousLabs/Sia/encoding" 16 ) 17 18 // sanityCheckWriter checks that the bytes written to w exactly match the 19 // bytes in buf. 20 type sanityCheckWriter struct { 21 w io.Writer 22 buf *bytes.Buffer 23 } 24 25 func (s sanityCheckWriter) Write(p []byte) (int, error) { 26 if !bytes.Equal(p, s.buf.Next(len(p))) { 27 panic("encoding mismatch") 28 } 29 return s.w.Write(p) 30 } 31 32 // MarshalSia implements the encoding.SiaMarshaler interface. 33 func (b Block) MarshalSia(w io.Writer) error { 34 if build.DEBUG { 35 // Sanity check: compare against the old encoding 36 buf := new(bytes.Buffer) 37 encoding.NewEncoder(buf).EncodeAll( 38 b.ParentID, 39 b.Nonce, 40 b.Timestamp, 41 b.MinerPayouts, 42 b.Transactions, 43 ) 44 w = sanityCheckWriter{w, buf} 45 } 46 47 e := encoding.NewEncoder(w) 48 e.Write(b.ParentID[:]) 49 e.Write(b.Nonce[:]) 50 e.WriteUint64(uint64(b.Timestamp)) 51 e.WriteInt(len(b.MinerPayouts)) 52 for i := range b.MinerPayouts { 53 b.MinerPayouts[i].MarshalSia(e) 54 } 55 e.WriteInt(len(b.Transactions)) 56 for i := range b.Transactions { 57 if err := b.Transactions[i].MarshalSia(e); err != nil { 58 return err 59 } 60 } 61 return e.Err() 62 } 63 64 // UnmarshalSia implements the encoding.SiaUnmarshaler interface. 65 func (b *Block) UnmarshalSia(r io.Reader) error { 66 if build.DEBUG { 67 // Sanity check: compare against the old decoding 68 buf := new(bytes.Buffer) 69 r = io.TeeReader(r, buf) 70 71 defer func() { 72 checkB := new(Block) 73 if err := encoding.UnmarshalAll(buf.Bytes(), 74 &checkB.ParentID, 75 &checkB.Nonce, 76 &checkB.Timestamp, 77 &checkB.MinerPayouts, 78 &checkB.Transactions, 79 ); err != nil { 80 // don't check invalid blocks 81 return 82 } 83 if crypto.HashObject(b) != crypto.HashObject(checkB) { 84 panic("decoding differs!") 85 } 86 }() 87 } 88 89 d := encoding.NewDecoder(r) 90 d.ReadFull(b.ParentID[:]) 91 d.ReadFull(b.Nonce[:]) 92 b.Timestamp = Timestamp(d.NextUint64()) 93 // MinerPayouts 94 b.MinerPayouts = make([]SiacoinOutput, d.NextPrefix(unsafe.Sizeof(SiacoinOutput{}))) 95 for i := range b.MinerPayouts { 96 b.MinerPayouts[i].UnmarshalSia(d) 97 } 98 // Transactions 99 b.Transactions = make([]Transaction, d.NextPrefix(unsafe.Sizeof(Transaction{}))) 100 for i := range b.Transactions { 101 b.Transactions[i].UnmarshalSia(d) 102 } 103 return d.Err() 104 } 105 106 // MarshalJSON marshales a block id as a hex string. 107 func (bid BlockID) MarshalJSON() ([]byte, error) { 108 return json.Marshal(bid.String()) 109 } 110 111 // String prints the block id in hex. 112 func (bid BlockID) String() string { 113 return fmt.Sprintf("%x", bid[:]) 114 } 115 116 // LoadString loads a BlockID from a string 117 func (bid *BlockID) LoadString(str string) error { 118 return (*crypto.Hash)(bid).LoadString(str) 119 } 120 121 // UnmarshalJSON decodes the json hex string of the block id. 122 func (bid *BlockID) UnmarshalJSON(b []byte) error { 123 return (*crypto.Hash)(bid).UnmarshalJSON(b) 124 } 125 126 // MarshalSia implements the encoding.SiaMarshaler interface. 127 func (cf CoveredFields) MarshalSia(w io.Writer) error { 128 e := encoding.NewEncoder(w) 129 e.WriteBool(cf.WholeTransaction) 130 fields := [][]uint64{ 131 cf.SiacoinInputs, 132 cf.SiacoinOutputs, 133 cf.FileContracts, 134 cf.FileContractRevisions, 135 cf.StorageProofs, 136 cf.SiafundInputs, 137 cf.SiafundOutputs, 138 cf.MinerFees, 139 cf.ArbitraryData, 140 cf.TransactionSignatures, 141 } 142 for _, f := range fields { 143 e.WriteInt(len(f)) 144 for _, u := range f { 145 e.WriteUint64(u) 146 } 147 } 148 return e.Err() 149 } 150 151 // MarshalSiaSize returns the encoded size of cf. 152 func (cf CoveredFields) MarshalSiaSize() (size int) { 153 size++ // WholeTransaction 154 size += 8 + len(cf.SiacoinInputs)*8 155 size += 8 + len(cf.SiacoinOutputs)*8 156 size += 8 + len(cf.FileContracts)*8 157 size += 8 + len(cf.FileContractRevisions)*8 158 size += 8 + len(cf.StorageProofs)*8 159 size += 8 + len(cf.SiafundInputs)*8 160 size += 8 + len(cf.SiafundOutputs)*8 161 size += 8 + len(cf.MinerFees)*8 162 size += 8 + len(cf.ArbitraryData)*8 163 size += 8 + len(cf.TransactionSignatures)*8 164 return 165 } 166 167 // UnmarshalSia implements the encoding.SiaUnmarshaler interface. 168 func (cf *CoveredFields) UnmarshalSia(r io.Reader) error { 169 d := encoding.NewDecoder(r) 170 buf := make([]byte, 1) 171 d.ReadFull(buf) 172 cf.WholeTransaction = (buf[0] == 1) 173 fields := []*[]uint64{ 174 &cf.SiacoinInputs, 175 &cf.SiacoinOutputs, 176 &cf.FileContracts, 177 &cf.FileContractRevisions, 178 &cf.StorageProofs, 179 &cf.SiafundInputs, 180 &cf.SiafundOutputs, 181 &cf.MinerFees, 182 &cf.ArbitraryData, 183 &cf.TransactionSignatures, 184 } 185 for i := range fields { 186 f := make([]uint64, d.NextPrefix(unsafe.Sizeof(uint64(0)))) 187 for i := range f { 188 f[i] = d.NextUint64() 189 } 190 *fields[i] = f 191 } 192 return d.Err() 193 } 194 195 // MarshalJSON implements the json.Marshaler interface. 196 func (c Currency) MarshalJSON() ([]byte, error) { 197 // Must enclosed the value in quotes; otherwise JS will convert it to a 198 // double and lose precision. 199 return []byte(`"` + c.String() + `"`), nil 200 } 201 202 // UnmarshalJSON implements the json.Unmarshaler interface. An error is 203 // returned if a negative number is provided. 204 func (c *Currency) UnmarshalJSON(b []byte) error { 205 // UnmarshalJSON does not expect quotes 206 b = bytes.Trim(b, `"`) 207 err := c.i.UnmarshalJSON(b) 208 if err != nil { 209 return err 210 } 211 if c.i.Sign() < 0 { 212 c.i = *big.NewInt(0) 213 return ErrNegativeCurrency 214 } 215 return nil 216 } 217 218 // MarshalSia implements the encoding.SiaMarshaler interface. It writes the 219 // byte-slice representation of the Currency's internal big.Int to w. Note 220 // that as the bytes of the big.Int correspond to the absolute value of the 221 // integer, there is no way to marshal a negative Currency. 222 func (c Currency) MarshalSia(w io.Writer) error { 223 // from math/big/arith.go 224 const ( 225 _m = ^big.Word(0) 226 _logS = _m>>8&1 + _m>>16&1 + _m>>32&1 227 _S = 1 << _logS // number of bytes per big.Word 228 ) 229 230 // get raw bits and seek to first zero byte 231 bits := c.i.Bits() 232 var i int 233 for i = len(bits)*_S - 1; i >= 0; i-- { 234 if bits[i/_S]>>(uint(i%_S)*8) != 0 { 235 break 236 } 237 } 238 239 // write length prefix 240 e := encoding.NewEncoder(w) 241 e.WriteInt(i + 1) 242 243 // write bytes 244 for ; i >= 0; i-- { 245 e.WriteByte(byte(bits[i/_S] >> (uint(i%_S) * 8))) 246 } 247 return e.Err() 248 } 249 250 // MarshalSiaSize returns the encoded size of c. 251 func (c Currency) MarshalSiaSize() int { 252 // from math/big/arith.go 253 const ( 254 _m = ^big.Word(0) 255 _logS = _m>>8&1 + _m>>16&1 + _m>>32&1 256 _S = 1 << _logS // number of bytes per big.Word 257 ) 258 259 // start with the number of Words * number of bytes per Word, then 260 // subtract trailing bytes that are 0 261 bits := c.i.Bits() 262 size := len(bits) * _S 263 zeros: 264 for i := len(bits) - 1; i >= 0; i-- { 265 for j := _S - 1; j >= 0; j-- { 266 if (bits[i] >> uintptr(j*8)) != 0 { 267 break zeros 268 } 269 size-- 270 } 271 } 272 return 8 + size // account for length prefix 273 } 274 275 // UnmarshalSia implements the encoding.SiaUnmarshaler interface. 276 func (c *Currency) UnmarshalSia(r io.Reader) error { 277 d := encoding.NewDecoder(r) 278 var dec Currency 279 dec.i.SetBytes(d.ReadPrefixedBytes()) 280 *c = dec 281 return d.Err() 282 } 283 284 // HumanString prints the Currency using human readable units. The unit used 285 // will be the largest unit that results in a value greater than 1. The value is 286 // rounded to 4 significant digits. 287 func (c Currency) HumanString() string { 288 pico := SiacoinPrecision.Div64(1e12) 289 if c.Cmp(pico) < 0 { 290 return c.String() + " H" 291 } 292 293 // iterate until we find a unit greater than c 294 mag := pico 295 unit := "" 296 for _, unit = range []string{"pS", "nS", "uS", "mS", "SC", "KS", "MS", "GS", "TS"} { 297 if c.Cmp(mag.Mul64(1e3)) < 0 { 298 break 299 } else if unit != "TS" { 300 // don't want to perform this multiply on the last iter; that 301 // would give us 1.235 TS instead of 1235 TS 302 mag = mag.Mul64(1e3) 303 } 304 } 305 306 num := new(big.Rat).SetInt(c.Big()) 307 denom := new(big.Rat).SetInt(mag.Big()) 308 res, _ := new(big.Rat).Mul(num, denom.Inv(denom)).Float64() 309 310 return fmt.Sprintf("%.4g %s", res, unit) 311 } 312 313 // String implements the fmt.Stringer interface. 314 func (c Currency) String() string { 315 return c.i.String() 316 } 317 318 // Scan implements the fmt.Scanner interface, allowing Currency values to be 319 // scanned from text. 320 func (c *Currency) Scan(s fmt.ScanState, ch rune) error { 321 var dec Currency 322 err := dec.i.Scan(s, ch) 323 if err != nil { 324 return err 325 } 326 if dec.i.Sign() < 0 { 327 return ErrNegativeCurrency 328 } 329 *c = dec 330 return nil 331 } 332 333 // MarshalSia implements the encoding.SiaMarshaler interface. 334 func (fc FileContract) MarshalSia(w io.Writer) error { 335 e := encoding.NewEncoder(w) 336 e.WriteUint64(fc.FileSize) 337 e.Write(fc.FileMerkleRoot[:]) 338 e.WriteUint64(uint64(fc.WindowStart)) 339 e.WriteUint64(uint64(fc.WindowEnd)) 340 fc.Payout.MarshalSia(e) 341 e.WriteInt(len(fc.ValidProofOutputs)) 342 for _, sco := range fc.ValidProofOutputs { 343 sco.MarshalSia(e) 344 } 345 e.WriteInt(len(fc.MissedProofOutputs)) 346 for _, sco := range fc.MissedProofOutputs { 347 sco.MarshalSia(e) 348 } 349 e.Write(fc.UnlockHash[:]) 350 e.WriteUint64(fc.RevisionNumber) 351 return e.Err() 352 } 353 354 // MarshalSiaSize returns the encoded size of fc. 355 func (fc FileContract) MarshalSiaSize() (size int) { 356 size += 8 // FileSize 357 size += len(fc.FileMerkleRoot) 358 size += 8 + 8 // WindowStart + WindowEnd 359 size += fc.Payout.MarshalSiaSize() 360 size += 8 361 for _, sco := range fc.ValidProofOutputs { 362 size += sco.Value.MarshalSiaSize() 363 size += len(sco.UnlockHash) 364 } 365 size += 8 366 for _, sco := range fc.MissedProofOutputs { 367 size += sco.Value.MarshalSiaSize() 368 size += len(sco.UnlockHash) 369 } 370 size += len(fc.UnlockHash) 371 size += 8 // RevisionNumber 372 return 373 } 374 375 // UnmarshalSia implements the encoding.SiaUnmarshaler interface. 376 func (fc *FileContract) UnmarshalSia(r io.Reader) error { 377 d := encoding.NewDecoder(r) 378 fc.FileSize = d.NextUint64() 379 d.ReadFull(fc.FileMerkleRoot[:]) 380 fc.WindowStart = BlockHeight(d.NextUint64()) 381 fc.WindowEnd = BlockHeight(d.NextUint64()) 382 fc.Payout.UnmarshalSia(d) 383 fc.ValidProofOutputs = make([]SiacoinOutput, d.NextPrefix(unsafe.Sizeof(SiacoinOutput{}))) 384 for i := range fc.ValidProofOutputs { 385 fc.ValidProofOutputs[i].UnmarshalSia(d) 386 } 387 fc.MissedProofOutputs = make([]SiacoinOutput, d.NextPrefix(unsafe.Sizeof(SiacoinOutput{}))) 388 for i := range fc.MissedProofOutputs { 389 fc.MissedProofOutputs[i].UnmarshalSia(d) 390 } 391 d.ReadFull(fc.UnlockHash[:]) 392 fc.RevisionNumber = d.NextUint64() 393 return d.Err() 394 } 395 396 // MarshalSia implements the encoding.SiaMarshaler interface. 397 func (fcr FileContractRevision) MarshalSia(w io.Writer) error { 398 e := encoding.NewEncoder(w) 399 e.Write(fcr.ParentID[:]) 400 fcr.UnlockConditions.MarshalSia(e) 401 e.WriteUint64(fcr.NewRevisionNumber) 402 e.WriteUint64(fcr.NewFileSize) 403 e.Write(fcr.NewFileMerkleRoot[:]) 404 e.WriteUint64(uint64(fcr.NewWindowStart)) 405 e.WriteUint64(uint64(fcr.NewWindowEnd)) 406 e.WriteInt(len(fcr.NewValidProofOutputs)) 407 for _, sco := range fcr.NewValidProofOutputs { 408 sco.MarshalSia(e) 409 } 410 e.WriteInt(len(fcr.NewMissedProofOutputs)) 411 for _, sco := range fcr.NewMissedProofOutputs { 412 sco.MarshalSia(e) 413 } 414 e.Write(fcr.NewUnlockHash[:]) 415 return e.Err() 416 } 417 418 // MarshalSiaSize returns the encoded size of fcr. 419 func (fcr FileContractRevision) MarshalSiaSize() (size int) { 420 size += len(fcr.ParentID) 421 size += fcr.UnlockConditions.MarshalSiaSize() 422 size += 8 // NewRevisionNumber 423 size += 8 // NewFileSize 424 size += len(fcr.NewFileMerkleRoot) 425 size += 8 + 8 // NewWindowStart + NewWindowEnd 426 size += 8 427 for _, sco := range fcr.NewValidProofOutputs { 428 size += sco.Value.MarshalSiaSize() 429 size += len(sco.UnlockHash) 430 } 431 size += 8 432 for _, sco := range fcr.NewMissedProofOutputs { 433 size += sco.Value.MarshalSiaSize() 434 size += len(sco.UnlockHash) 435 } 436 size += len(fcr.NewUnlockHash) 437 return 438 } 439 440 // UnmarshalSia implements the encoding.SiaUnmarshaler interface. 441 func (fcr *FileContractRevision) UnmarshalSia(r io.Reader) error { 442 d := encoding.NewDecoder(r) 443 d.ReadFull(fcr.ParentID[:]) 444 fcr.UnlockConditions.UnmarshalSia(d) 445 fcr.NewRevisionNumber = d.NextUint64() 446 fcr.NewFileSize = d.NextUint64() 447 d.ReadFull(fcr.NewFileMerkleRoot[:]) 448 fcr.NewWindowStart = BlockHeight(d.NextUint64()) 449 fcr.NewWindowEnd = BlockHeight(d.NextUint64()) 450 fcr.NewValidProofOutputs = make([]SiacoinOutput, d.NextPrefix(unsafe.Sizeof(SiacoinOutput{}))) 451 for i := range fcr.NewValidProofOutputs { 452 fcr.NewValidProofOutputs[i].UnmarshalSia(d) 453 } 454 fcr.NewMissedProofOutputs = make([]SiacoinOutput, d.NextPrefix(unsafe.Sizeof(SiacoinOutput{}))) 455 for i := range fcr.NewMissedProofOutputs { 456 fcr.NewMissedProofOutputs[i].UnmarshalSia(d) 457 } 458 d.ReadFull(fcr.NewUnlockHash[:]) 459 return d.Err() 460 } 461 462 // MarshalJSON marshals an id as a hex string. 463 func (fcid FileContractID) MarshalJSON() ([]byte, error) { 464 return json.Marshal(fcid.String()) 465 } 466 467 // String prints the id in hex. 468 func (fcid FileContractID) String() string { 469 return fmt.Sprintf("%x", fcid[:]) 470 } 471 472 // UnmarshalJSON decodes the json hex string of the id. 473 func (fcid *FileContractID) UnmarshalJSON(b []byte) error { 474 return (*crypto.Hash)(fcid).UnmarshalJSON(b) 475 } 476 477 // MarshalJSON marshals an id as a hex string. 478 func (oid OutputID) MarshalJSON() ([]byte, error) { 479 return json.Marshal(oid.String()) 480 } 481 482 // String prints the id in hex. 483 func (oid OutputID) String() string { 484 return fmt.Sprintf("%x", oid[:]) 485 } 486 487 // UnmarshalJSON decodes the json hex string of the id. 488 func (oid *OutputID) UnmarshalJSON(b []byte) error { 489 return (*crypto.Hash)(oid).UnmarshalJSON(b) 490 } 491 492 // MarshalSia implements the encoding.SiaMarshaler interface. 493 func (sci SiacoinInput) MarshalSia(w io.Writer) error { 494 e := encoding.NewEncoder(w) 495 e.Write(sci.ParentID[:]) 496 sci.UnlockConditions.MarshalSia(e) 497 return e.Err() 498 } 499 500 // UnmarshalSia implements the encoding.SiaUnmarshaler interface. 501 func (sci *SiacoinInput) UnmarshalSia(r io.Reader) error { 502 d := encoding.NewDecoder(r) 503 d.ReadFull(sci.ParentID[:]) 504 sci.UnlockConditions.UnmarshalSia(d) 505 return d.Err() 506 } 507 508 // MarshalSia implements the encoding.SiaMarshaler interface. 509 func (sco SiacoinOutput) MarshalSia(w io.Writer) error { 510 e := encoding.NewEncoder(w) 511 sco.Value.MarshalSia(e) 512 e.Write(sco.UnlockHash[:]) 513 return e.Err() 514 } 515 516 // UnmarshalSia implements the encoding.SiaUnmarshaler interface. 517 func (sco *SiacoinOutput) UnmarshalSia(r io.Reader) error { 518 d := encoding.NewDecoder(r) 519 sco.Value.UnmarshalSia(d) 520 d.ReadFull(sco.UnlockHash[:]) 521 return d.Err() 522 } 523 524 // MarshalJSON marshals an id as a hex string. 525 func (scoid SiacoinOutputID) MarshalJSON() ([]byte, error) { 526 return json.Marshal(scoid.String()) 527 } 528 529 // String prints the id in hex. 530 func (scoid SiacoinOutputID) String() string { 531 return fmt.Sprintf("%x", scoid[:]) 532 } 533 534 // UnmarshalJSON decodes the json hex string of the id. 535 func (scoid *SiacoinOutputID) UnmarshalJSON(b []byte) error { 536 return (*crypto.Hash)(scoid).UnmarshalJSON(b) 537 } 538 539 // MarshalSia implements the encoding.SiaMarshaler interface. 540 func (sfi SiafundInput) MarshalSia(w io.Writer) error { 541 e := encoding.NewEncoder(w) 542 e.Write(sfi.ParentID[:]) 543 sfi.UnlockConditions.MarshalSia(e) 544 e.Write(sfi.ClaimUnlockHash[:]) 545 return e.Err() 546 } 547 548 // UnmarshalSia implements the encoding.SiaUnmarshaler interface. 549 func (sfi *SiafundInput) UnmarshalSia(r io.Reader) error { 550 d := encoding.NewDecoder(r) 551 d.ReadFull(sfi.ParentID[:]) 552 sfi.UnlockConditions.UnmarshalSia(d) 553 d.ReadFull(sfi.ClaimUnlockHash[:]) 554 return d.Err() 555 } 556 557 // MarshalSia implements the encoding.SiaMarshaler interface. 558 func (sfo SiafundOutput) MarshalSia(w io.Writer) error { 559 e := encoding.NewEncoder(w) 560 sfo.Value.MarshalSia(e) 561 e.Write(sfo.UnlockHash[:]) 562 sfo.ClaimStart.MarshalSia(e) 563 return e.Err() 564 } 565 566 // UnmarshalSia implements the encoding.SiaUnmarshaler interface. 567 func (sfo *SiafundOutput) UnmarshalSia(r io.Reader) error { 568 d := encoding.NewDecoder(r) 569 sfo.Value.UnmarshalSia(d) 570 d.ReadFull(sfo.UnlockHash[:]) 571 sfo.ClaimStart.UnmarshalSia(d) 572 return d.Err() 573 } 574 575 // MarshalJSON marshals an id as a hex string. 576 func (sfoid SiafundOutputID) MarshalJSON() ([]byte, error) { 577 return json.Marshal(sfoid.String()) 578 } 579 580 // String prints the id in hex. 581 func (sfoid SiafundOutputID) String() string { 582 return fmt.Sprintf("%x", sfoid[:]) 583 } 584 585 // UnmarshalJSON decodes the json hex string of the id. 586 func (sfoid *SiafundOutputID) UnmarshalJSON(b []byte) error { 587 return (*crypto.Hash)(sfoid).UnmarshalJSON(b) 588 } 589 590 // MarshalSia implements the encoding.SiaMarshaler interface. 591 func (spk SiaPublicKey) MarshalSia(w io.Writer) error { 592 e := encoding.NewEncoder(w) 593 e.Write(spk.Algorithm[:]) 594 e.WritePrefixedBytes(spk.Key) 595 return e.Err() 596 } 597 598 // UnmarshalSia implements the encoding.SiaUnmarshaler interface. 599 func (spk *SiaPublicKey) UnmarshalSia(r io.Reader) error { 600 d := encoding.NewDecoder(r) 601 d.ReadFull(spk.Algorithm[:]) 602 spk.Key = d.ReadPrefixedBytes() 603 return d.Err() 604 } 605 606 // LoadString is the inverse of SiaPublicKey.String(). 607 func (spk *SiaPublicKey) LoadString(s string) { 608 parts := strings.Split(s, ":") 609 if len(parts) != 2 { 610 return 611 } 612 var err error 613 spk.Key, err = hex.DecodeString(parts[1]) 614 if err != nil { 615 spk.Key = nil 616 return 617 } 618 copy(spk.Algorithm[:], []byte(parts[0])) 619 } 620 621 // String defines how to print a SiaPublicKey - hex is used to keep things 622 // compact during logging. The key type prefix and lack of a checksum help to 623 // separate it from a sia address. 624 func (spk *SiaPublicKey) String() string { 625 return spk.Algorithm.String() + ":" + fmt.Sprintf("%x", spk.Key) 626 } 627 628 // MarshalJSON marshals a specifier as a string. 629 func (s Specifier) MarshalJSON() ([]byte, error) { 630 return json.Marshal(s.String()) 631 } 632 633 // String returns the specifier as a string, trimming any trailing zeros. 634 func (s Specifier) String() string { 635 var i int 636 for i = range s { 637 if s[i] == 0 { 638 break 639 } 640 } 641 return string(s[:i]) 642 } 643 644 // UnmarshalJSON decodes the json string of the specifier. 645 func (s *Specifier) UnmarshalJSON(b []byte) error { 646 var str string 647 if err := json.Unmarshal(b, &str); err != nil { 648 return err 649 } 650 copy(s[:], str) 651 return nil 652 } 653 654 // MarshalSia implements the encoding.SiaMarshaler interface. 655 func (sp *StorageProof) MarshalSia(w io.Writer) error { 656 e := encoding.NewEncoder(w) 657 e.Write(sp.ParentID[:]) 658 e.Write(sp.Segment[:]) 659 e.WriteInt(len(sp.HashSet)) 660 for i := range sp.HashSet { 661 e.Write(sp.HashSet[i][:]) 662 } 663 return e.Err() 664 } 665 666 // UnmarshalSia implements the encoding.SiaUnmarshaler interface. 667 func (sp *StorageProof) UnmarshalSia(r io.Reader) error { 668 d := encoding.NewDecoder(r) 669 d.ReadFull(sp.ParentID[:]) 670 d.ReadFull(sp.Segment[:]) 671 sp.HashSet = make([]crypto.Hash, d.NextPrefix(unsafe.Sizeof(crypto.Hash{}))) 672 for i := range sp.HashSet { 673 d.ReadFull(sp.HashSet[i][:]) 674 } 675 return d.Err() 676 } 677 678 // MarshalSia implements the encoding.SiaMarshaler interface. 679 func (t Transaction) MarshalSia(w io.Writer) error { 680 if build.DEBUG { 681 // Sanity check: compare against the old encoding 682 buf := new(bytes.Buffer) 683 encoding.NewEncoder(buf).EncodeAll( 684 t.SiacoinInputs, 685 t.SiacoinOutputs, 686 t.FileContracts, 687 t.FileContractRevisions, 688 t.StorageProofs, 689 t.SiafundInputs, 690 t.SiafundOutputs, 691 t.MinerFees, 692 t.ArbitraryData, 693 t.TransactionSignatures, 694 ) 695 w = sanityCheckWriter{w, buf} 696 } 697 698 e := encoding.NewEncoder(w) 699 t.marshalSiaNoSignatures(e) 700 e.WriteInt(len((t.TransactionSignatures))) 701 for i := range t.TransactionSignatures { 702 t.TransactionSignatures[i].MarshalSia(e) 703 } 704 return e.Err() 705 } 706 707 // marshalSiaNoSignatures is a helper function for calculating certain hashes 708 // that do not include the transaction's signatures. 709 func (t Transaction) marshalSiaNoSignatures(w io.Writer) { 710 e := encoding.NewEncoder(w) 711 e.WriteInt(len((t.SiacoinInputs))) 712 for i := range t.SiacoinInputs { 713 t.SiacoinInputs[i].MarshalSia(e) 714 } 715 e.WriteInt(len((t.SiacoinOutputs))) 716 for i := range t.SiacoinOutputs { 717 t.SiacoinOutputs[i].MarshalSia(e) 718 } 719 e.WriteInt(len((t.FileContracts))) 720 for i := range t.FileContracts { 721 t.FileContracts[i].MarshalSia(e) 722 } 723 e.WriteInt(len((t.FileContractRevisions))) 724 for i := range t.FileContractRevisions { 725 t.FileContractRevisions[i].MarshalSia(e) 726 } 727 e.WriteInt(len((t.StorageProofs))) 728 for i := range t.StorageProofs { 729 t.StorageProofs[i].MarshalSia(e) 730 } 731 e.WriteInt(len((t.SiafundInputs))) 732 for i := range t.SiafundInputs { 733 t.SiafundInputs[i].MarshalSia(e) 734 } 735 e.WriteInt(len((t.SiafundOutputs))) 736 for i := range t.SiafundOutputs { 737 t.SiafundOutputs[i].MarshalSia(e) 738 } 739 e.WriteInt(len((t.MinerFees))) 740 for i := range t.MinerFees { 741 t.MinerFees[i].MarshalSia(e) 742 } 743 e.WriteInt(len((t.ArbitraryData))) 744 for i := range t.ArbitraryData { 745 e.WritePrefixedBytes(t.ArbitraryData[i]) 746 } 747 } 748 749 // MarshalSiaSize returns the encoded size of t. 750 func (t Transaction) MarshalSiaSize() (size int) { 751 size += 8 752 for _, sci := range t.SiacoinInputs { 753 size += len(sci.ParentID) 754 size += sci.UnlockConditions.MarshalSiaSize() 755 } 756 size += 8 757 for _, sco := range t.SiacoinOutputs { 758 size += sco.Value.MarshalSiaSize() 759 size += len(sco.UnlockHash) 760 } 761 size += 8 762 for i := range t.FileContracts { 763 size += t.FileContracts[i].MarshalSiaSize() 764 } 765 size += 8 766 for i := range t.FileContractRevisions { 767 size += t.FileContractRevisions[i].MarshalSiaSize() 768 } 769 size += 8 770 for _, sp := range t.StorageProofs { 771 size += len(sp.ParentID) 772 size += len(sp.Segment) 773 size += 8 + len(sp.HashSet)*crypto.HashSize 774 } 775 size += 8 776 for _, sfi := range t.SiafundInputs { 777 size += len(sfi.ParentID) 778 size += len(sfi.ClaimUnlockHash) 779 size += sfi.UnlockConditions.MarshalSiaSize() 780 } 781 size += 8 782 for _, sfo := range t.SiafundOutputs { 783 size += sfo.Value.MarshalSiaSize() 784 size += len(sfo.UnlockHash) 785 size += sfo.ClaimStart.MarshalSiaSize() 786 } 787 size += 8 788 for i := range t.MinerFees { 789 size += t.MinerFees[i].MarshalSiaSize() 790 } 791 size += 8 792 for i := range t.ArbitraryData { 793 size += 8 + len(t.ArbitraryData[i]) 794 } 795 size += 8 796 for _, ts := range t.TransactionSignatures { 797 size += len(ts.ParentID) 798 size += 8 // ts.PublicKeyIndex 799 size += 8 // ts.Timelock 800 size += ts.CoveredFields.MarshalSiaSize() 801 size += 8 + len(ts.Signature) 802 } 803 804 // Sanity check against the slower method. 805 if build.DEBUG { 806 expectedSize := len(encoding.Marshal(t)) 807 if expectedSize != size { 808 panic("Transaction size different from expected size.") 809 } 810 } 811 return 812 } 813 814 // UnmarshalSia implements the encoding.SiaUnmarshaler interface. 815 func (t *Transaction) UnmarshalSia(r io.Reader) error { 816 d := encoding.NewDecoder(r) 817 t.SiacoinInputs = make([]SiacoinInput, d.NextPrefix(unsafe.Sizeof(SiacoinInput{}))) 818 for i := range t.SiacoinInputs { 819 t.SiacoinInputs[i].UnmarshalSia(d) 820 } 821 t.SiacoinOutputs = make([]SiacoinOutput, d.NextPrefix(unsafe.Sizeof(SiacoinOutput{}))) 822 for i := range t.SiacoinOutputs { 823 t.SiacoinOutputs[i].UnmarshalSia(d) 824 } 825 t.FileContracts = make([]FileContract, d.NextPrefix(unsafe.Sizeof(FileContract{}))) 826 for i := range t.FileContracts { 827 t.FileContracts[i].UnmarshalSia(d) 828 } 829 t.FileContractRevisions = make([]FileContractRevision, d.NextPrefix(unsafe.Sizeof(FileContractRevision{}))) 830 for i := range t.FileContractRevisions { 831 t.FileContractRevisions[i].UnmarshalSia(d) 832 } 833 t.StorageProofs = make([]StorageProof, d.NextPrefix(unsafe.Sizeof(StorageProof{}))) 834 for i := range t.StorageProofs { 835 t.StorageProofs[i].UnmarshalSia(d) 836 } 837 t.SiafundInputs = make([]SiafundInput, d.NextPrefix(unsafe.Sizeof(SiafundInput{}))) 838 for i := range t.SiafundInputs { 839 t.SiafundInputs[i].UnmarshalSia(d) 840 } 841 t.SiafundOutputs = make([]SiafundOutput, d.NextPrefix(unsafe.Sizeof(SiafundOutput{}))) 842 for i := range t.SiafundOutputs { 843 t.SiafundOutputs[i].UnmarshalSia(d) 844 } 845 t.MinerFees = make([]Currency, d.NextPrefix(unsafe.Sizeof(Currency{}))) 846 for i := range t.MinerFees { 847 t.MinerFees[i].UnmarshalSia(d) 848 } 849 t.ArbitraryData = make([][]byte, d.NextPrefix(unsafe.Sizeof([]byte{}))) 850 for i := range t.ArbitraryData { 851 t.ArbitraryData[i] = d.ReadPrefixedBytes() 852 } 853 t.TransactionSignatures = make([]TransactionSignature, d.NextPrefix(unsafe.Sizeof(TransactionSignature{}))) 854 for i := range t.TransactionSignatures { 855 t.TransactionSignatures[i].UnmarshalSia(d) 856 } 857 return d.Err() 858 } 859 860 // MarshalJSON marshals an id as a hex string. 861 func (tid TransactionID) MarshalJSON() ([]byte, error) { 862 return json.Marshal(tid.String()) 863 } 864 865 // String prints the id in hex. 866 func (tid TransactionID) String() string { 867 return fmt.Sprintf("%x", tid[:]) 868 } 869 870 // UnmarshalJSON decodes the json hex string of the id. 871 func (tid *TransactionID) UnmarshalJSON(b []byte) error { 872 return (*crypto.Hash)(tid).UnmarshalJSON(b) 873 } 874 875 // MarshalSia implements the encoding.SiaMarshaler interface. 876 func (ts TransactionSignature) MarshalSia(w io.Writer) error { 877 e := encoding.NewEncoder(w) 878 e.Write(ts.ParentID[:]) 879 e.WriteUint64(ts.PublicKeyIndex) 880 e.WriteUint64(uint64(ts.Timelock)) 881 ts.CoveredFields.MarshalSia(e) 882 e.WritePrefixedBytes(ts.Signature) 883 return e.Err() 884 } 885 886 // UnmarshalSia implements the encoding.SiaUnmarshaler interface. 887 func (ts *TransactionSignature) UnmarshalSia(r io.Reader) error { 888 d := encoding.NewDecoder(r) 889 d.ReadFull(ts.ParentID[:]) 890 ts.PublicKeyIndex = d.NextUint64() 891 ts.Timelock = BlockHeight(d.NextUint64()) 892 ts.CoveredFields.UnmarshalSia(d) 893 ts.Signature = d.ReadPrefixedBytes() 894 return d.Err() 895 } 896 897 // MarshalSia implements the encoding.SiaMarshaler interface. 898 func (uc UnlockConditions) MarshalSia(w io.Writer) error { 899 e := encoding.NewEncoder(w) 900 e.WriteUint64(uint64(uc.Timelock)) 901 e.WriteInt(len(uc.PublicKeys)) 902 for _, spk := range uc.PublicKeys { 903 spk.MarshalSia(e) 904 } 905 e.WriteUint64(uc.SignaturesRequired) 906 return e.Err() 907 } 908 909 // MarshalSiaSize returns the encoded size of uc. 910 func (uc UnlockConditions) MarshalSiaSize() (size int) { 911 size += 8 // Timelock 912 size += 8 // length prefix for PublicKeys 913 for _, spk := range uc.PublicKeys { 914 size += len(spk.Algorithm) 915 size += 8 + len(spk.Key) 916 } 917 size += 8 // SignaturesRequired 918 return 919 } 920 921 // UnmarshalSia implements the encoding.SiaUnmarshaler interface. 922 func (uc *UnlockConditions) UnmarshalSia(r io.Reader) error { 923 d := encoding.NewDecoder(r) 924 uc.Timelock = BlockHeight(d.NextUint64()) 925 uc.PublicKeys = make([]SiaPublicKey, d.NextPrefix(unsafe.Sizeof(SiaPublicKey{}))) 926 for i := range uc.PublicKeys { 927 uc.PublicKeys[i].UnmarshalSia(d) 928 } 929 uc.SignaturesRequired = d.NextUint64() 930 return d.Err() 931 } 932 933 // MarshalJSON is implemented on the unlock hash to always produce a hex string 934 // upon marshalling. 935 func (uh UnlockHash) MarshalJSON() ([]byte, error) { 936 return json.Marshal(uh.String()) 937 } 938 939 // UnmarshalJSON is implemented on the unlock hash to recover an unlock hash 940 // that has been encoded to a hex string. 941 func (uh *UnlockHash) UnmarshalJSON(b []byte) error { 942 // Check the length of b. 943 if len(b) != crypto.HashSize*2+UnlockHashChecksumSize*2+2 && len(b) != crypto.HashSize*2+2 { 944 return ErrUnlockHashWrongLen 945 } 946 return uh.LoadString(string(b[1 : len(b)-1])) 947 } 948 949 // String returns the hex representation of the unlock hash as a string - this 950 // includes a checksum. 951 func (uh UnlockHash) String() string { 952 uhChecksum := crypto.HashObject(uh) 953 return fmt.Sprintf("%x%x", uh[:], uhChecksum[:UnlockHashChecksumSize]) 954 } 955 956 // LoadString loads a hex representation (including checksum) of an unlock hash 957 // into an unlock hash object. An error is returned if the string is invalid or 958 // fails the checksum. 959 func (uh *UnlockHash) LoadString(strUH string) error { 960 // Check the length of strUH. 961 if len(strUH) != crypto.HashSize*2+UnlockHashChecksumSize*2 { 962 return ErrUnlockHashWrongLen 963 } 964 965 // Decode the unlock hash. 966 var byteUnlockHash []byte 967 var checksum []byte 968 _, err := fmt.Sscanf(strUH[:crypto.HashSize*2], "%x", &byteUnlockHash) 969 if err != nil { 970 return err 971 } 972 973 // Decode and verify the checksum. 974 _, err = fmt.Sscanf(strUH[crypto.HashSize*2:], "%x", &checksum) 975 if err != nil { 976 return err 977 } 978 expectedChecksum := crypto.HashBytes(byteUnlockHash) 979 if !bytes.Equal(expectedChecksum[:UnlockHashChecksumSize], checksum) { 980 return ErrInvalidUnlockHashChecksum 981 } 982 983 copy(uh[:], byteUnlockHash[:]) 984 return nil 985 } 986 987 // Scan implements the fmt.Scanner interface, allowing UnlockHash values to be 988 // scanned from text. 989 func (uh *UnlockHash) Scan(s fmt.ScanState, ch rune) error { 990 s.SkipSpace() 991 tok, err := s.Token(false, nil) 992 if err != nil { 993 return err 994 } 995 return uh.LoadString(string(tok)) 996 }