Commit 74a879a8 authored by Christopher Schinnerl's avatar Christopher Schinnerl

merge generateKeys and generateKeysReverse

parent b13c9818
Pipeline #42982166 passed with stages
in 28 minutes and 1 second
......@@ -201,7 +201,7 @@ func SignTransaction(txn *types.Transaction, seed modules.Seed, toSign []crypto.
var keyIndex uint64
const keysPerBatch = 1000
for len(keys) < 1e6 {
for _, sk := range generateKeys(seed, keyIndex, keyIndex+keysPerBatch) {
for _, sk := range generateKeys(seed, keyIndex, keyIndex+keysPerBatch, false) {
keys[sk.UnlockConditions.UnlockHash()] = sk
}
keyIndex += keysPerBatch
......
......@@ -71,7 +71,7 @@ func (s *seedScanner) numKeys() uint64 {
// generateKeys generates n additional keys from the seedScanner's seed.
func (s *seedScanner) generateKeys(n uint64) {
initialProgress := s.numKeys()
for i, k := range generateKeys(s.seed, initialProgress, n) {
for i, k := range generateKeys(s.seed, initialProgress, n, false) {
s.keys[k.UnlockConditions.UnlockHash()] = initialProgress + uint64(i)
}
}
......
......@@ -44,33 +44,13 @@ func generateSpendableKey(seed modules.Seed, index uint64) spendableKey {
}
}
// generateKeys generates n keys from seed, starting from index start.
func generateKeys(seed modules.Seed, start, n uint64) []spendableKey {
// generate in parallel, one goroutine per core.
keys := make([]spendableKey, n)
var wg sync.WaitGroup
wg.Add(runtime.NumCPU())
for cpu := 0; cpu < runtime.NumCPU(); cpu++ {
go func(offset uint64) {
defer wg.Done()
for i := offset; i < n; i += uint64(runtime.NumCPU()) {
// NOTE: don't bother trying to optimize generateSpendableKey;
// profiling shows that ed25519 key generation consumes far
// more CPU time than encoding or hashing.
keys[i] = generateSpendableKey(seed, start+i)
}
}(uint64(cpu))
}
wg.Wait()
return keys
}
// generateKeysReverse generates n keys from seed, starting from index start
// and moving towards index 0. If n is too big and would result in a negative
// index, it will return fewer than n spendable keys without throwing an error.
func generateKeysReverse(seed modules.Seed, start, n uint64) []spendableKey {
// generateKeys generates n keys from seed, starting from index start. If
// reverse is set to true, it will start with index start and move towards
// index 0. If n is too big and would result in a negative index, it will
// return fewer than n spendable keys without throwing an error.
func generateKeys(seed modules.Seed, start, n uint64, reverse bool) []spendableKey {
// Make sure that we don't generate below index 0.
if n > start+1 {
if reverse && n > start+1 {
n = start + 1
}
// generate in parallel, one goroutine per core.
......@@ -80,11 +60,17 @@ func generateKeysReverse(seed modules.Seed, start, n uint64) []spendableKey {
for cpu := 0; cpu < runtime.NumCPU(); cpu++ {
go func(offset uint64) {
defer wg.Done()
var index uint64
for i := offset; i < n; i += uint64(runtime.NumCPU()) {
// NOTE: don't bother trying to optimize generateSpendableKey;
// profiling shows that ed25519 key generation consumes far
// more CPU time than encoding or hashing.
keys[i] = generateSpendableKey(seed, start-i)
if reverse {
index = start - i
} else {
index = start + i
}
keys[i] = generateSpendableKey(seed, index)
}
}(uint64(cpu))
}
......@@ -126,7 +112,7 @@ func (w *Wallet) regenerateLookahead(start uint64) {
maxKeys := maxLookahead(start)
existingKeys := uint64(len(w.lookahead))
for i, k := range generateKeys(w.primarySeed, start+existingKeys, maxKeys-existingKeys) {
for i, k := range generateKeys(w.primarySeed, start+existingKeys, maxKeys-existingKeys, false) {
w.lookahead[k.UnlockConditions.UnlockHash()] = start + existingKeys + uint64(i)
}
}
......@@ -134,7 +120,7 @@ func (w *Wallet) regenerateLookahead(start uint64) {
// integrateSeed generates n spendableKeys from the seed and loads them into
// the wallet.
func (w *Wallet) integrateSeed(seed modules.Seed, n uint64) {
for _, sk := range generateKeys(seed, 0, n) {
for _, sk := range generateKeys(seed, 0, n, false) {
w.keys[sk.UnlockConditions.UnlockHash()] = sk
}
}
......@@ -157,7 +143,7 @@ func (w *Wallet) nextPrimarySeedAddresses(tx *bolt.Tx, n uint64) ([]types.Unlock
// Integrate the next keys into the wallet, and return the unlock
// conditions. Also remove new keys from the future keys and update them
// according to new progress
spendableKeys := generateKeys(w.primarySeed, progress, n)
spendableKeys := generateKeys(w.primarySeed, progress, n, false)
ucs := make([]types.UnlockConditions, 0, len(spendableKeys))
for _, spendableKey := range spendableKeys {
w.keys[spendableKey.UnlockConditions.UnlockHash()] = spendableKey
......
......@@ -511,8 +511,8 @@ func TestSweepSeedCoinsAndFunds(t *testing.T) {
// TestGenerateKeys tests that the generateKeys function correctly generates a
// key for every index specified.
func TestGenerateKeys(t *testing.T) {
keys := generateKeys(modules.Seed{}, 1000, 4000)
keysReverse := generateKeysReverse(modules.Seed{}, 4999, 4000)
keys := generateKeys(modules.Seed{}, 1000, 4000, false)
keysReverse := generateKeys(modules.Seed{}, 4999, 4000, true)
for i, k := range keys {
if len(k.UnlockConditions.PublicKeys) == 0 {
t.Errorf("index %v was skipped", i)
......@@ -521,8 +521,13 @@ func TestGenerateKeys(t *testing.T) {
t.Fatal("keys are not equal")
}
}
// This should only return 1 key.
if keys := generateKeysReverse(modules.Seed{}, 0, 2); len(keys) != 1 {
// This should only return 1 key. The one at index 0.
keys = generateKeys(modules.Seed{}, 0, 2, true)
if len(keys) != 1 {
t.Fatalf("should've returned 1 key but was %v", len(keys))
}
expectedKey := generateKeys(modules.Seed{}, 0, 1, false)[0]
if keys[0].UnlockConditions.UnlockHash() != expectedKey.UnlockConditions.UnlockHash() {
t.Fatalf("key should be the one generated at index 0")
}
}
......@@ -46,7 +46,7 @@ func (w *Wallet) advanceSeedLookahead(index uint64) (bool, error) {
newProgress := index + 1
// Add spendable keys and remove them from lookahead
spendableKeys := generateKeys(w.primarySeed, progress, newProgress-progress)
spendableKeys := generateKeys(w.primarySeed, progress, newProgress-progress, false)
for _, key := range spendableKeys {
w.keys[key.UnlockConditions.UnlockHash()] = key
delete(w.lookahead, key.UnlockConditions.UnlockHash())
......
......@@ -158,7 +158,7 @@ func (w *Wallet) LastAddresses(n uint64) ([]types.UnlockHash, error) {
return []types.UnlockHash{}, err
}
// Generate the keys.
keys := generateKeysReverse(w.primarySeed, seedProgress-1, n)
keys := generateKeys(w.primarySeed, seedProgress-1, n, true)
uhs := make([]types.UnlockHash, len(keys))
for i := range keys {
uhs[i] = keys[i].UnlockConditions.UnlockHash()
......
......@@ -376,7 +376,7 @@ func TestAdvanceLookaheadNoRescan(t *testing.T) {
// choose 10 keys in the lookahead and remember them
var receivingAddresses []types.UnlockHash
for _, sk := range generateKeys(wt.wallet.primarySeed, progress, 10) {
for _, sk := range generateKeys(wt.wallet.primarySeed, progress, 10, false) {
sco := types.SiacoinOutput{
UnlockHash: sk.UnlockConditions.UnlockHash(),
Value: types.NewCurrency64(1e3),
......
......@@ -2,6 +2,7 @@ package wallet
import (
"errors"
"math"
"path/filepath"
"testing"
"time"
......@@ -531,7 +532,21 @@ func TestWalletLastAddresses(t *testing.T) {
if err != nil {
t.Fatal(err)
}
// Make sure the returned addresses
// Make sure the returned addresses are the same and have the reversed
// order of the created ones.
for i := range wag.Addresses {
if addresses[i] != wlag.Addresses[len(wlag.Addresses)-1-i] {
t.Fatal("addresses don't match for i =", i)
}
}
// Get MaxUint64 addresses in reverse order. This should still only return
// n addresses.
wlag, err = testNode.WalletLastAddressesGet(math.MaxUint64)
if err != nil {
t.Fatal(err)
}
// Make sure the returned addresses are the same and have the reversed
// order of the created ones.
for i := range wag.Addresses {
if addresses[i] != wlag.Addresses[len(wlag.Addresses)-1-i] {
t.Fatal("addresses don't match for i =", i)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment