// LoadString loads a hex representation (including checksum) of an unlock hash // into an unlock hash object. An error is returned if the string is invalid or // fails the checksum. func (uh *UnlockHash) LoadString(strUH string) error { // Check the length of strUH. if len(strUH) != crypto.HashSize*2+UnlockHashChecksumSize*2 { return ErrUnlockHashWrongLen } // Decode the unlock hash. var byteUnlockHash []byte var checksum []byte _, err := fmt.Sscanf(strUH[:crypto.HashSize*2], "%x", &byteUnlockHash) if err != nil { return err } // Decode and verify the checksum. _, err = fmt.Sscanf(strUH[crypto.HashSize*2:], "%x", &checksum) if err != nil { return err } expectedChecksum := crypto.HashBytes(byteUnlockHash) if !bytes.Equal(expectedChecksum[:UnlockHashChecksumSize], checksum) { return ErrInvalidUnlockHashChecksum } copy(uh[:], byteUnlockHash[:]) return nil }
// LoadString loads a hex representation (including checksum) of an unlock hash // into an unlock hash object. An error is returned if the string is invalid or // fails the checksum. func (uh *UnlockHash) LoadString(strUH string) error { // Check the length of strUH. if len(strUH) != crypto.HashSize*2+UnlockHashChecksumSize*2 && len(strUH) != crypto.HashSize*2 { return ErrUnlockHashWrongLen } // Decode the unlock hash. var byteUnlockHash []byte var checksum []byte _, err := fmt.Sscanf(strUH[:crypto.HashSize*2], "%x", &byteUnlockHash) if err != nil { return err } // Decode the checksum, if provided. if len(strUH) == crypto.HashSize*2+UnlockHashChecksumSize*2 { _, err = fmt.Sscanf(strUH[crypto.HashSize*2:], "%x", &checksum) if err != nil { return err } // Verify the checksum - leave uh as-is unless the checksum is valid. expectedChecksum := crypto.HashBytes(byteUnlockHash) if bytes.Compare(expectedChecksum[:UnlockHashChecksumSize], checksum) != 0 { return ErrInvalidUnlockHashChecksum } } copy(uh[:], byteUnlockHash[:]) return nil }
// SigHash returns the hash of the fields in a transaction covered by a given // signature. See CoveredFields for more details. func (t Transaction) SigHash(i int) crypto.Hash { cf := t.TransactionSignatures[i].CoveredFields var signedData []byte if cf.WholeTransaction { signedData = encoding.MarshalAll( t.SiacoinInputs, t.SiacoinOutputs, t.FileContracts, t.FileContractRevisions, t.StorageProofs, t.SiafundInputs, t.SiafundOutputs, t.MinerFees, t.ArbitraryData, t.TransactionSignatures[i].ParentID, t.TransactionSignatures[i].PublicKeyIndex, t.TransactionSignatures[i].Timelock, ) } else { for _, input := range cf.SiacoinInputs { signedData = append(signedData, encoding.Marshal(t.SiacoinInputs[input])...) } for _, output := range cf.SiacoinOutputs { signedData = append(signedData, encoding.Marshal(t.SiacoinOutputs[output])...) } for _, contract := range cf.FileContracts { signedData = append(signedData, encoding.Marshal(t.FileContracts[contract])...) } for _, revision := range cf.FileContractRevisions { signedData = append(signedData, encoding.Marshal(t.FileContractRevisions[revision])...) } for _, storageProof := range cf.StorageProofs { signedData = append(signedData, encoding.Marshal(t.StorageProofs[storageProof])...) } for _, siafundInput := range cf.SiafundInputs { signedData = append(signedData, encoding.Marshal(t.SiafundInputs[siafundInput])...) } for _, siafundOutput := range cf.SiafundOutputs { signedData = append(signedData, encoding.Marshal(t.SiafundOutputs[siafundOutput])...) } for _, minerFee := range cf.MinerFees { signedData = append(signedData, encoding.Marshal(t.MinerFees[minerFee])...) } for _, arbData := range cf.ArbitraryData { signedData = append(signedData, encoding.Marshal(t.ArbitraryData[arbData])...) } } for _, sig := range cf.TransactionSignatures { signedData = append(signedData, encoding.Marshal(t.TransactionSignatures[sig])...) } return crypto.HashBytes(signedData) }
// SolveBlock takes a block, target, and number of iterations as input and // tries to find a block that meets the target. This function can take a long // time to complete, and should not be called with a lock. func (m *Miner) SolveBlock(b types.Block, target types.Target) (types.Block, bool) { // Assemble the header. merkleRoot := b.MerkleRoot() header := make([]byte, 80) copy(header, b.ParentID[:]) binary.LittleEndian.PutUint64(header[40:48], uint64(b.Timestamp)) copy(header[48:], merkleRoot[:]) nonce := (*uint64)(unsafe.Pointer(&header[32])) for i := 0; i < iterationsPerAttempt; i++ { id := crypto.HashBytes(header) if bytes.Compare(target[:], id[:]) >= 0 { copy(b.Nonce[:], header[32:40]) return b, true } *nonce++ } return b, false }
// TestBlockHeader checks that BlockHeader returns the correct value, and that // the hash is consistent with the old method for obtaining the hash. func TestBlockHeader(t *testing.T) { var b Block b.ParentID[1] = 1 b.Nonce[2] = 2 b.Timestamp = 3 b.MinerPayouts = []SiacoinOutput{{Value: NewCurrency64(4)}} b.Transactions = []Transaction{{ArbitraryData: [][]byte{[]byte{'5'}}}} id1 := b.ID() id2 := BlockID(crypto.HashBytes(encoding.Marshal(b.Header()))) id3 := BlockID(crypto.HashAll( b.ParentID, b.Nonce, b.Timestamp, b.MerkleRoot(), )) if id1 != id2 || id2 != id3 || id3 != id1 { t.Error("Methods for getting block id don't return the same results") } }
// CreateAnnouncement will take a host announcement and encode it, returning // the exact []byte that should be added to the arbitrary data of a // transaction. func CreateAnnouncement(addr NetAddress, pk types.SiaPublicKey, sk crypto.SecretKey) (signedAnnouncement []byte, err error) { if err := addr.IsValid(); err != nil { return nil, err } // Create the HostAnnouncement and marshal it. annBytes := encoding.Marshal(HostAnnouncement{ Specifier: PrefixHostAnnouncement, NetAddress: addr, PublicKey: pk, }) // Create a signature for the announcement. annHash := crypto.HashBytes(annBytes) sig, err := crypto.SignHash(annHash, sk) if err != nil { return nil, err } // Return the signed announcement. return append(annBytes, sig[:]...), nil }