// saveSiafundTracking save the addresses that track siafunds. func (w *Wallet) saveSiafundTracking(filepath string) error { // Put the siafund tracking addresses into a slice and write to disk. siafundSlice := make([]types.UnlockHash, 0, len(w.siafundAddresses)) for sa, _ := range w.siafundAddresses { siafundSlice = append(siafundSlice, sa) } return encoding.WriteFile(filepath, siafundSlice) }
// saveKeys saves the current set of keys known to the wallet to a file. func (w *Wallet) saveKeys(filepath string) error { // Convert the key map to a slice and write to disk. keySlice := make([]savedKey, 0, len(w.keys)) for _, key := range w.keys { _, exists := w.visibleAddresses[key.unlockConditions.UnlockHash()] keySlice = append(keySlice, savedKey{key.secretKey, key.unlockConditions, exists}) } return encoding.WriteFile(filepath, keySlice) }
// TestPrintKeyInfo probes the printKeyInfo function. func TestPrintKeyInfo(t *testing.T) { if testing.Short() { t.SkipNow() } testDir := build.TempDir("siakg", "TestPrintKeyInfo") // Check that a corrupted header or version will trigger an error. keyname := "headerCheck" _, err := generateKeys(1, 1, testDir, keyname) if err != nil { t.Fatal(err) } var kp, badKP KeyPair keyfile := filepath.Join(testDir, keyname+"_Key0"+FileExtension) err = encoding.ReadFile(keyfile, &kp) if err != nil { t.Fatal(err) } badKP = kp badKP.Header = "bad" err = encoding.WriteFile(keyfile, badKP) if err != nil { t.Fatal(err) } err = printKeyInfo(keyfile) if err != ErrUnknownHeader { t.Error("Expected ErrUnknownHeader:", err) } badKP = kp badKP.Version = "bad" err = encoding.WriteFile(keyfile, badKP) if err != nil { t.Fatal(err) } err = printKeyInfo(keyfile) if err != ErrUnknownVersion { t.Error("Expected ErrUnknownVersion:", err) } }
// TestVerifyKeys proves the verifyKeys function. func TestVerifyKeys(t *testing.T) { if testing.Short() { t.SkipNow() } testDir := build.TempDir("siag", "TestVerifyKeys") // Check that a corrupted header or version will trigger an error. keyname := "headerCheck" uc, err := generateKeys(1, 1, testDir, keyname) if err != nil { t.Fatal(err) } var kp, badKP KeyPair keyfile := filepath.Join(testDir, keyname+"_Key0"+FileExtension) err = encoding.ReadFile(keyfile, &kp) if err != nil { t.Fatal(err) } badKP = kp badKP.Header = "bad" err = encoding.WriteFile(keyfile, badKP) if err != nil { t.Fatal(err) } err = verifyKeys(uc, testDir, keyname) if err != ErrUnknownHeader { t.Error("Expected ErrUnknownHeader:", err) } badKP = kp badKP.Version = "bad" err = encoding.WriteFile(keyfile, badKP) if err != nil { t.Fatal(err) } err = verifyKeys(uc, testDir, keyname) if err != ErrUnknownVersion { t.Error("Expected ErrUnknownVersion:", err) } // Create sets of keys that cover all boundaries from 0 of 1 to 5 of 9. // This is to check for errors in the keycheck calculations. for i := 1; i < 5; i++ { for j := i; j < 9; j++ { keyname := "genuine" + strconv.Itoa(i) + strconv.Itoa(j) uc, err := generateKeys(i, j, testDir, keyname) if err != nil { t.Fatal(err) } // Check that the validate under standard conditions. err = verifyKeys(uc, testDir, keyname) if err != nil { t.Error(err) } // Provide the wrong keyname to simulate a file does not exist error. err = verifyKeys(uc, testDir, "wrongName") if err == nil { t.Error("Expecting an error") } // Corrupt the unlock conditions of the files 1 by 1, and see that each // file is checked for validity. for k := 0; k < j; k++ { // Load, corrupt, and then save the keypair. This corruption // alters the UnlockConditions. var originalKP, badKP KeyPair keyfile := filepath.Join(testDir, keyname+"_Key"+strconv.Itoa(k)+FileExtension) err := encoding.ReadFile(keyfile, &originalKP) if err != nil { t.Fatal(err) } badKP = originalKP badKP.UnlockConditions.PublicKeys = nil err = encoding.WriteFile(keyfile, badKP) if err != nil { t.Fatal(err) } // Run verifyKeys with the corrupted file. err = verifyKeys(uc, testDir, keyname) if err == nil { t.Error("Expecting error after corrupting unlock conditions") } // Restore the original keyfile. err = encoding.WriteFile(keyfile, originalKP) if err != nil { t.Fatal(err) } // Verify that things work again. err = verifyKeys(uc, testDir, keyname) if err != nil { t.Fatal(err) } } // Corrupt the secret keys of the files 1 by 1, and see that each secret // key is checked for validity. for k := 0; k < j; k++ { // Load, corrupt, and then save the keypair. This corruption // alters the secret key. var originalKP, badKP KeyPair keyfile := filepath.Join(testDir, keyname+"_Key"+strconv.Itoa(k)+FileExtension) err := encoding.ReadFile(keyfile, &originalKP) if err != nil { t.Fatal(err) } badKP = originalKP badKP.SecretKey[0]++ err = encoding.WriteFile(keyfile, badKP) if err != nil { t.Fatal(err) } // Run verifyKeys with the corrupted file. err = verifyKeys(uc, testDir, keyname) if err == nil { t.Error("Expecting error after corrupting unlock conditions") } // Restore the original keyfile. err = encoding.WriteFile(keyfile, originalKP) if err != nil { t.Fatal(err) } // Verify that things work again. err = verifyKeys(uc, testDir, keyname) if err != nil { t.Fatal(err) } } } } }
// generateKeys generates a set of keys and saves them to disk. func generateKeys(requiredKeys int, totalKeys int, folder string, keyname string) (types.UnlockConditions, error) { // Check that the inputs have sane values. if requiredKeys < 1 { return types.UnlockConditions{}, ErrInsecureAddress } if totalKeys < requiredKeys { return types.UnlockConditions{}, ErrUnspendableAddress } // Generate 'TotalKeys', filling out everything except the unlock // conditions. keys := make([]KeyPair, totalKeys) pubKeys := make([]crypto.PublicKey, totalKeys) for i := range keys { var err error keys[i].Header = FileHeader keys[i].Version = FileVersion keys[i].Index = i keys[i].SecretKey, pubKeys[i], err = crypto.GenerateSignatureKeys() if err != nil { return types.UnlockConditions{}, err } } // Generate the unlock conditions and add them to each KeyPair object. This // must be done second because the keypairs can't be given unlock // conditions until the PublicKeys have all been added. unlockConditions := types.UnlockConditions{ Timelock: 0, SignaturesRequired: uint64(requiredKeys), } for i := range keys { unlockConditions.PublicKeys = append(unlockConditions.PublicKeys, types.SiaPublicKey{ Algorithm: types.SignatureEd25519, Key: pubKeys[i][:], }) } for i := range keys { keys[i].UnlockConditions = unlockConditions } // Save the KeyPairs to disk. if folder != "" { err := os.MkdirAll(folder, 0700) if err != nil { return types.UnlockConditions{}, err } } for i, key := range keys { keyFilename := filepath.Join(folder, keyname+"_Key"+strconv.Itoa(i)+FileExtension) _, err := os.Stat(keyFilename) if !os.IsNotExist(err) { if err != nil { return types.UnlockConditions{}, err } return types.UnlockConditions{}, ErrOverwrite } err = encoding.WriteFile(keyFilename, key) if err != nil { return types.UnlockConditions{}, err } } return unlockConditions, nil }