diff options
author | John Lee <64482439+algojohnlee@users.noreply.github.com> | 2022-10-19 20:43:40 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-19 20:43:40 -0400 |
commit | 10fbfbb054dee6c4cbcebc7bdabe568a0738f491 (patch) | |
tree | 519c1bb6f06bfd0a203b9dff719a61adee57d851 | |
parent | 281689d3b9df0db0cce8fcfa3bc61c6017c019e5 (diff) | |
parent | 4a285b6b71d4645911e393194e75c106e9e31038 (diff) |
Merge pull request #4673 from Algo-devops-service/relbeta3.11.1v3.11.1-beta
-rw-r--r-- | buildnumber.dat | 2 | ||||
-rw-r--r-- | cmd/goal/commands.go | 4 | ||||
-rw-r--r-- | cmd/pingpong/runCmd.go | 17 | ||||
-rw-r--r-- | crypto/batchverifier.go | 5 | ||||
-rw-r--r-- | crypto/batchverifier_test.go | 27 | ||||
-rw-r--r-- | daemon/algod/api/client/restClient.go | 74 | ||||
-rw-r--r-- | daemon/kmd/client/client.go | 8 | ||||
-rw-r--r-- | ledger/accountdb.go | 22 | ||||
-rw-r--r-- | ledger/catchpointwriter_test.go | 6 | ||||
-rw-r--r-- | ledger/catchupaccessor.go | 121 | ||||
-rw-r--r-- | ledger/catchupaccessor_test.go | 144 | ||||
-rw-r--r-- | libgoal/libgoal.go | 22 | ||||
-rw-r--r-- | shared/pingpong/accounts.go | 20 | ||||
-rw-r--r-- | shared/pingpong/config.go | 9 | ||||
-rw-r--r-- | test/e2e-go/features/catchup/catchpointCatchup_test.go | 2 | ||||
-rw-r--r-- | test/e2e-go/restAPI/restClient_test.go | 6 | ||||
-rw-r--r-- | tools/debug/determaccount/main.go | 45 |
17 files changed, 372 insertions, 162 deletions
diff --git a/buildnumber.dat b/buildnumber.dat index 573541ac9..d00491fd7 100644 --- a/buildnumber.dat +++ b/buildnumber.dat @@ -1 +1 @@ -0 +1 diff --git a/cmd/goal/commands.go b/cmd/goal/commands.go index c6103d259..8fb4550c0 100644 --- a/cmd/goal/commands.go +++ b/cmd/goal/commands.go @@ -29,9 +29,6 @@ import ( "github.com/spf13/cobra/doc" "golang.org/x/crypto/ssh/terminal" - algodclient "github.com/algorand/go-algorand/daemon/algod/api/client" - kmdclient "github.com/algorand/go-algorand/daemon/kmd/client" - "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/daemon/algod/api/spec/common" "github.com/algorand/go-algorand/data/bookkeeping" @@ -381,7 +378,6 @@ func getGoalClient(dataDir string, clientType libgoal.ClientType) (client libgoa if err != nil { return } - client.SetAPIVersionAffinity(algodclient.APIVersionV2, kmdclient.APIVersionV1) return } diff --git a/cmd/pingpong/runCmd.go b/cmd/pingpong/runCmd.go index 9df0052ac..d49cea843 100644 --- a/cmd/pingpong/runCmd.go +++ b/cmd/pingpong/runCmd.go @@ -72,7 +72,8 @@ var pidFile string var cpuprofile string var randSeed int64 var deterministicKeys bool -var generatedAccountsCount uint32 +var generatedAccountsCount uint64 +var generatedAccountsOffset uint64 var generatedAccountSampleMethod string var configPath string @@ -118,8 +119,9 @@ func init() { runCmd.Flags().StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`") runCmd.Flags().Int64Var(&randSeed, "seed", 0, "input to math/rand.Seed(), defaults to time.Now().UnixNano()") runCmd.Flags().BoolVar(&deterministicKeys, "deterministicKeys", false, "Draw from set of netgoal-created accounts using deterministic keys") - runCmd.Flags().Uint32Var(&generatedAccountsCount, "genaccounts", 0, "The total number of accounts pre-generated by netgoal") - runCmd.Flags().StringVar(&generatedAccountSampleMethod, "gensamplemethod", "random", "The method of sampling from the total # of pre-generated accounts") + runCmd.Flags().Uint64Var(&generatedAccountsCount, "genaccounts", 0, "The total number of accounts pre-generated by netgoal") + runCmd.Flags().Uint64Var(&generatedAccountsOffset, "genaccountsoffset", 0, "The initial offset for sampling from the total # of pre-generated accounts") + runCmd.Flags().StringVar(&generatedAccountSampleMethod, "gensamplemethod", "", "The method of sampling from the total # of pre-generated accounts") } var runCmd = &cobra.Command{ @@ -378,16 +380,23 @@ var runCmd = &cobra.Command{ if !deterministicKeys && generatedAccountsCount > 0 { reportErrorf("generatedAccountsCount requires deterministicKeys=true") } - if deterministicKeys && numAccounts > generatedAccountsCount { + if deterministicKeys && uint64(numAccounts) > generatedAccountsCount { reportErrorf("numAccounts must be <= generatedAccountsCount") } cfg.DeterministicKeys = deterministicKeys || cfg.DeterministicKeys if generatedAccountsCount != 0 { cfg.GeneratedAccountsCount = generatedAccountsCount } + if generatedAccountsOffset != 0 { + cfg.GeneratedAccountsOffset = generatedAccountsOffset + } if generatedAccountSampleMethod != "" { cfg.GeneratedAccountSampleMethod = generatedAccountSampleMethod } + // check if numAccounts is greater than the length of the mnemonic list, if provided + if cfg.DeterministicKeys && cfg.NumPartAccounts > uint32(len(cfg.GeneratedAccountsMnemonics)) { + reportErrorf("numAccounts is greater than number of account mnemonics provided") + } cfg.SetDefaultWeights() err = cfg.Check() diff --git a/crypto/batchverifier.go b/crypto/batchverifier.go index 9a46aac4b..96cf5e850 100644 --- a/crypto/batchverifier.go +++ b/crypto/batchverifier.go @@ -38,6 +38,7 @@ package crypto import "C" import ( "errors" + "runtime" "unsafe" ) @@ -172,6 +173,10 @@ func batchVerificationImpl(messages [][]byte, publicKeys []SignatureVerifier, si C.size_t(len(messages)), (*C.int)(unsafe.Pointer(valid))) + runtime.KeepAlive(messages) + runtime.KeepAlive(publicKeys) + runtime.KeepAlive(signatures) + failed = make([]bool, numberOfSignatures) for i := 0; i < numberOfSignatures; i++ { cint := *(*C.int)(unsafe.Pointer(uintptr(valid) + uintptr(i*C.sizeof_int))) diff --git a/crypto/batchverifier_test.go b/crypto/batchverifier_test.go index b0dc2f0fb..7c5455703 100644 --- a/crypto/batchverifier_test.go +++ b/crypto/batchverifier_test.go @@ -18,6 +18,7 @@ package crypto import ( "math/rand" + "runtime" "testing" "github.com/stretchr/testify/require" @@ -193,3 +194,29 @@ func TestBatchVerifierIndividualResultsAllValid(t *testing.T) { } } } + +func TestBatchVerifierGC(t *testing.T) { + partitiontest.PartitionTest(t) + + const n = 128 + for i := 0; i < 100; i++ { + t.Run("", func(t *testing.T) { + t.Parallel() + + bv := MakeBatchVerifierWithHint(n) + var s Seed + + for i := 0; i < n; i++ { + msg := randString() + RandBytes(s[:]) + sigSecrets := GenerateSignatureSecrets(s) + sig := sigSecrets.Sign(msg) + bv.EnqueueSignature(sigSecrets.SignatureVerifier, msg, sig) + } + require.NoError(t, bv.Verify()) + + runtime.GC() + }) + } + +} diff --git a/daemon/algod/api/client/restClient.go b/daemon/algod/api/client/restClient.go index b5d25816d..2bece32a6 100644 --- a/daemon/algod/api/client/restClient.go +++ b/daemon/algod/api/client/restClient.go @@ -46,16 +46,6 @@ const ( maxRawResponseBytes = 50e6 ) -// APIVersion is used to define which server side API version would be used when making http requests to the server -type APIVersion string - -const ( - // APIVersionV1 suggests that the RestClient would use v1 calls whenever it's available for the given request. - APIVersionV1 APIVersion = "v1" - // APIVersionV2 suggests that the RestClient would use v2 calls whenever it's available for the given request. - APIVersionV2 APIVersion = "v2" -) - // rawRequestPaths is a set of paths where the body should not be urlencoded var rawRequestPaths = map[string]bool{ "/v1/transactions": true, @@ -91,27 +81,18 @@ func (e HTTPError) Error() string { // RestClient manages the REST interface for a calling user. type RestClient struct { - serverURL url.URL - apiToken string - versionAffinity APIVersion + serverURL url.URL + apiToken string } // MakeRestClient is the factory for constructing a RestClient for a given endpoint func MakeRestClient(url url.URL, apiToken string) RestClient { return RestClient{ - serverURL: url, - apiToken: apiToken, - versionAffinity: APIVersionV1, + serverURL: url, + apiToken: apiToken, } } -// SetAPIVersionAffinity sets the client affinity to use a specific version of the API -func (client *RestClient) SetAPIVersionAffinity(affinity APIVersion) (previousAffinity APIVersion) { - previousAffinity = client.versionAffinity - client.versionAffinity = affinity - return -} - // filterASCII filter out the non-ascii printable characters out of the given input string. // It's used as a security qualifier before adding network provided data into an error message. // The function allows only characters in the range of [32..126], which excludes all the @@ -251,31 +232,13 @@ func (client RestClient) post(response interface{}, path string, request interfa // the StatusResponse includes data like the consensus version and current round // Not supported func (client RestClient) Status() (response generatedV2.NodeStatusResponse, err error) { - switch client.versionAffinity { - case APIVersionV2: - err = client.get(&response, "/v2/status", nil) - default: - var nodeStatus v1.NodeStatus - err = client.get(&nodeStatus, "/v1/status", nil) - if err == nil { - response = fillNodeStatusResponse(nodeStatus) - } - } + err = client.get(&response, "/v2/status", nil) return } // WaitForBlock returns the node status after waiting for the given round. func (client RestClient) WaitForBlock(round basics.Round) (response generatedV2.NodeStatusResponse, err error) { - switch client.versionAffinity { - case APIVersionV2: - err = client.get(&response, fmt.Sprintf("/v2/status/wait-for-block-after/%d/", round), nil) - default: - var nodeStatus v1.NodeStatus - err = client.get(&nodeStatus, fmt.Sprintf("/v1/status/wait-for-block-after/%d/", round), nil) - if err == nil { - response = fillNodeStatusResponse(nodeStatus) - } - } + err = client.get(&response, fmt.Sprintf("/v2/status/wait-for-block-after/%d/", round), nil) return } @@ -302,17 +265,7 @@ func fillNodeStatusResponse(nodeStatus v1.NodeStatus) generatedV2.NodeStatusResp // blocks on the node end // Not supported func (client RestClient) StatusAfterBlock(blockNum uint64) (response generatedV2.NodeStatusResponse, err error) { - switch client.versionAffinity { - case APIVersionV2: - err = client.get(&response, fmt.Sprintf("/v2/status/wait-for-block-after/%d", blockNum), nil) - default: - var nodeStatus v1.NodeStatus - err = client.get(&nodeStatus, fmt.Sprintf("/v1/status/wait-for-block-after/%d", blockNum), nil) - if err == nil { - response = fillNodeStatusResponse(nodeStatus) - } - } - + err = client.get(&response, fmt.Sprintf("/v2/status/wait-for-block-after/%d", blockNum), nil) return } @@ -546,16 +499,9 @@ func (client RestClient) Block(round uint64) (response v1.Block, err error) { // RawBlock gets the encoded, raw msgpack block for the given round func (client RestClient) RawBlock(round uint64) (response []byte, err error) { - switch client.versionAffinity { - case APIVersionV2: - var blob Blob - err = client.getRaw(&blob, fmt.Sprintf("/v2/blocks/%d", round), rawFormat{Format: "msgpack"}) - response = blob - default: - var raw v1.RawBlock - err = client.getRaw(&raw, fmt.Sprintf("/v1/block/%d", round), rawblockParams{1}) - response = raw - } + var blob Blob + err = client.getRaw(&blob, fmt.Sprintf("/v2/blocks/%d", round), rawFormat{Format: "msgpack"}) + response = blob return } diff --git a/daemon/kmd/client/client.go b/daemon/kmd/client/client.go index ee0c5f131..413e3e8d7 100644 --- a/daemon/kmd/client/client.go +++ b/daemon/kmd/client/client.go @@ -25,14 +25,6 @@ const ( timeoutSecs = 120 ) -// APIVersion is used to define which server side API version would be used when making http requests to the server -type APIVersion string - -const ( - // APIVersionV1 suggests that the RestClient would use v1 calls whenever it's available for the given request. - APIVersionV1 APIVersion = "v1" -) - // KMDClient is the client used to interact with the kmd API over its socket type KMDClient struct { httpClient http.Client diff --git a/ledger/accountdb.go b/ledger/accountdb.go index 5a92ab919..264687b20 100644 --- a/ledger/accountdb.go +++ b/ledger/accountdb.go @@ -371,6 +371,8 @@ type normalizedAccountBalance struct { normalizedBalance uint64 // encodedResources provides the encoded form of the resources encodedResources map[basics.CreatableIndex][]byte + // partial balance indicates that the original account balance was split into multiple parts in catchpoint creation time + partialBalance bool } // prepareNormalizedBalancesV5 converts an array of encodedBalanceRecordV5 into an equal size array of normalizedAccountBalances. @@ -427,12 +429,22 @@ func prepareNormalizedBalancesV6(bals []encodedBalanceRecordV6, proto config.Con normalizedAccountBalances[i].accountData.MicroAlgos, proto) normalizedAccountBalances[i].encodedAccountData = balance.AccountData - normalizedAccountBalances[i].accountHashes = make([][]byte, 1+len(balance.Resources)) - normalizedAccountBalances[i].accountHashes[0] = accountHashBuilderV6(balance.Address, &normalizedAccountBalances[i].accountData, balance.AccountData) + curHashIdx := 0 + if balance.ExpectingMoreEntries { + // There is a single chunk in the catchpoint file with ExpectingMoreEntries + // set to false for this account. There may be multiple chunks with + // ExpectingMoreEntries set to true. In this case, we do not have to add the + // account's own hash to accountHashes. + normalizedAccountBalances[i].accountHashes = make([][]byte, len(balance.Resources)) + normalizedAccountBalances[i].partialBalance = true + } else { + normalizedAccountBalances[i].accountHashes = make([][]byte, 1+len(balance.Resources)) + normalizedAccountBalances[i].accountHashes[0] = accountHashBuilderV6(balance.Address, &normalizedAccountBalances[i].accountData, balance.AccountData) + curHashIdx++ + } if len(balance.Resources) > 0 { normalizedAccountBalances[i].resources = make(map[basics.CreatableIndex]resourcesData, len(balance.Resources)) normalizedAccountBalances[i].encodedResources = make(map[basics.CreatableIndex][]byte, len(balance.Resources)) - resIdx := 0 for cidx, res := range balance.Resources { var resData resourcesData err = protocol.Decode(res, &resData) @@ -447,10 +459,10 @@ func prepareNormalizedBalancesV6(bals []encodedBalanceRecordV6, proto config.Con } else { err = fmt.Errorf("unknown creatable for addr %s, aidx %d, data %v", balance.Address.String(), cidx, resData) } - normalizedAccountBalances[i].accountHashes[resIdx+1] = resourcesHashBuilderV6(balance.Address, basics.CreatableIndex(cidx), ctype, resData.UpdateRound, res) + normalizedAccountBalances[i].accountHashes[curHashIdx] = resourcesHashBuilderV6(balance.Address, basics.CreatableIndex(cidx), ctype, resData.UpdateRound, res) normalizedAccountBalances[i].resources[basics.CreatableIndex(cidx)] = resData normalizedAccountBalances[i].encodedResources[basics.CreatableIndex(cidx)] = res - resIdx++ + curHashIdx++ } } } diff --git a/ledger/catchpointwriter_test.go b/ledger/catchpointwriter_test.go index e5765e506..8c8493372 100644 --- a/ledger/catchpointwriter_test.go +++ b/ledger/catchpointwriter_test.go @@ -394,6 +394,9 @@ func TestFullCatchpointWriter(t *testing.T) { require.NoError(t, err) } + err = accessor.BuildMerkleTrie(context.Background(), nil) + require.NoError(t, err) + err = l.trackerDBs.Wdb.Atomic(func(ctx context.Context, tx *sql.Tx) error { err := applyCatchpointStagingBalances(ctx, tx, 0, 0) return err @@ -701,6 +704,9 @@ func TestFullCatchpointWriterOverflowAccounts(t *testing.T) { require.NoError(t, err) } + err = accessor.BuildMerkleTrie(context.Background(), nil) + require.NoError(t, err) + err = l.trackerDBs.Wdb.Atomic(func(ctx context.Context, tx *sql.Tx) error { err := applyCatchpointStagingBalances(ctx, tx, 0, 0) return err diff --git a/ledger/catchupaccessor.go b/ledger/catchupaccessor.go index 3c2f6acee..2a12377d3 100644 --- a/ledger/catchupaccessor.go +++ b/ledger/catchupaccessor.go @@ -91,10 +91,46 @@ type CatchpointCatchupAccessor interface { Ledger() (l CatchupAccessorClientLedger) } -// CatchpointCatchupAccessorImpl is the concrete implementation of the CatchpointCatchupAccessor interface -type CatchpointCatchupAccessorImpl struct { +type stagingWriter interface { + writeBalances(context.Context, []normalizedAccountBalance) error + writeCreatables(context.Context, []normalizedAccountBalance) error + writeHashes(context.Context, []normalizedAccountBalance) error + isShared() bool +} + +type stagingWriterImpl struct { + wdb db.Accessor +} + +func (w *stagingWriterImpl) writeBalances(ctx context.Context, balances []normalizedAccountBalance) error { + return w.wdb.Atomic(func(ctx context.Context, tx *sql.Tx) (err error) { + return writeCatchpointStagingBalances(ctx, tx, balances) + }) +} + +func (w *stagingWriterImpl) writeCreatables(ctx context.Context, balances []normalizedAccountBalance) error { + return w.wdb.Atomic(func(ctx context.Context, tx *sql.Tx) error { + return writeCatchpointStagingCreatable(ctx, tx, balances) + }) +} + +func (w *stagingWriterImpl) writeHashes(ctx context.Context, balances []normalizedAccountBalance) error { + return w.wdb.Atomic(func(ctx context.Context, tx *sql.Tx) error { + err := writeCatchpointStagingHashes(ctx, tx, balances) + return err + }) +} + +func (w *stagingWriterImpl) isShared() bool { + return w.wdb.IsSharedCacheConnection() +} + +// catchpointCatchupAccessorImpl is the concrete implementation of the CatchpointCatchupAccessor interface +type catchpointCatchupAccessorImpl struct { ledger *Ledger + stagingWriter stagingWriter + // log copied from ledger log logging.Logger @@ -135,14 +171,15 @@ type CatchupAccessorClientLedger interface { // MakeCatchpointCatchupAccessor creates a CatchpointCatchupAccessor given a ledger func MakeCatchpointCatchupAccessor(ledger *Ledger, log logging.Logger) CatchpointCatchupAccessor { - return &CatchpointCatchupAccessorImpl{ - ledger: ledger, - log: log, + return &catchpointCatchupAccessorImpl{ + ledger: ledger, + stagingWriter: &stagingWriterImpl{wdb: ledger.trackerDB().Wdb}, + log: log, } } // GetState returns the current state of the catchpoint catchup -func (c *CatchpointCatchupAccessorImpl) GetState(ctx context.Context) (state CatchpointCatchupState, err error) { +func (c *catchpointCatchupAccessorImpl) GetState(ctx context.Context) (state CatchpointCatchupState, err error) { var istate uint64 istate, err = readCatchpointStateUint64(ctx, c.ledger.trackerDB().Rdb.Handle, catchpointStateCatchupState) if err != nil { @@ -153,7 +190,7 @@ func (c *CatchpointCatchupAccessorImpl) GetState(ctx context.Context) (state Cat } // SetState set the state of the catchpoint catchup -func (c *CatchpointCatchupAccessorImpl) SetState(ctx context.Context, state CatchpointCatchupState) (err error) { +func (c *catchpointCatchupAccessorImpl) SetState(ctx context.Context, state CatchpointCatchupState) (err error) { if state < CatchpointCatchupStateInactive || state > catchpointCatchupStateLast { return fmt.Errorf("invalid catchpoint catchup state provided : %d", state) } @@ -165,7 +202,7 @@ func (c *CatchpointCatchupAccessorImpl) SetState(ctx context.Context, state Catc } // GetLabel returns the current catchpoint catchup label -func (c *CatchpointCatchupAccessorImpl) GetLabel(ctx context.Context) (label string, err error) { +func (c *catchpointCatchupAccessorImpl) GetLabel(ctx context.Context) (label string, err error) { label, err = readCatchpointStateString(ctx, c.ledger.trackerDB().Rdb.Handle, catchpointStateCatchupLabel) if err != nil { return "", fmt.Errorf("unable to read catchpoint catchup state '%s': %v", catchpointStateCatchupLabel, err) @@ -174,7 +211,7 @@ func (c *CatchpointCatchupAccessorImpl) GetLabel(ctx context.Context) (label str } // SetLabel set the catchpoint catchup label -func (c *CatchpointCatchupAccessorImpl) SetLabel(ctx context.Context, label string) (err error) { +func (c *catchpointCatchupAccessorImpl) SetLabel(ctx context.Context, label string) (err error) { // verify it's parsable : _, _, err = ledgercore.ParseCatchpointLabel(label) if err != nil { @@ -188,7 +225,7 @@ func (c *CatchpointCatchupAccessorImpl) SetLabel(ctx context.Context, label stri } // ResetStagingBalances resets the current staging balances, preparing for a new set of balances to be added -func (c *CatchpointCatchupAccessorImpl) ResetStagingBalances(ctx context.Context, newCatchup bool) (err error) { +func (c *catchpointCatchupAccessorImpl) ResetStagingBalances(ctx context.Context, newCatchup bool) (err error) { wdb := c.ledger.trackerDB().Wdb if !newCatchup { c.ledger.setSynchronousMode(ctx, c.ledger.synchronousMode) @@ -246,7 +283,7 @@ type CatchpointCatchupAccessorProgress struct { } // ProgressStagingBalances deserialize the given bytes as a temporary staging balances -func (c *CatchpointCatchupAccessorImpl) ProgressStagingBalances(ctx context.Context, sectionName string, bytes []byte, progress *CatchpointCatchupAccessorProgress) (err error) { +func (c *catchpointCatchupAccessorImpl) ProgressStagingBalances(ctx context.Context, sectionName string, bytes []byte, progress *CatchpointCatchupAccessorProgress) (err error) { if sectionName == "content.msgpack" { return c.processStagingContent(ctx, bytes, progress) } @@ -259,7 +296,7 @@ func (c *CatchpointCatchupAccessorImpl) ProgressStagingBalances(ctx context.Cont } // processStagingContent deserialize the given bytes as a temporary staging balances content -func (c *CatchpointCatchupAccessorImpl) processStagingContent(ctx context.Context, bytes []byte, progress *CatchpointCatchupAccessorProgress) (err error) { +func (c *catchpointCatchupAccessorImpl) processStagingContent(ctx context.Context, bytes []byte, progress *CatchpointCatchupAccessorProgress) (err error) { if progress.SeenHeader { return fmt.Errorf("CatchpointCatchupAccessorImpl::processStagingContent: content chunk already seen") } @@ -307,12 +344,11 @@ func (c *CatchpointCatchupAccessorImpl) processStagingContent(ctx context.Contex } // processStagingBalances deserialize the given bytes as a temporary staging balances -func (c *CatchpointCatchupAccessorImpl) processStagingBalances(ctx context.Context, bytes []byte, progress *CatchpointCatchupAccessorProgress) (err error) { +func (c *catchpointCatchupAccessorImpl) processStagingBalances(ctx context.Context, bytes []byte, progress *CatchpointCatchupAccessorProgress) (err error) { if !progress.SeenHeader { return fmt.Errorf("CatchpointCatchupAccessorImpl::processStagingBalances: content chunk was missing") } - wdb := c.ledger.trackerDB().Wdb start := time.Now() ledgerProcessstagingbalancesCount.Inc(nil) @@ -440,16 +476,13 @@ func (c *CatchpointCatchupAccessorImpl) processStagingBalances(ctx context.Conte wg.Add(1) go func() { defer wg.Done() - errBalances = wdb.Atomic(func(ctx context.Context, tx *sql.Tx) (err error) { - start := time.Now() - err = writeCatchpointStagingBalances(ctx, tx, normalizedAccountBalances) - durBalances = time.Since(start) - return err - }) + start := time.Now() + errBalances = c.stagingWriter.writeBalances(ctx, normalizedAccountBalances) + durBalances = time.Since(start) }() // on a in-memory database, wait for the writer to finish before starting the new writer - if wdb.IsSharedCacheConnection() { + if c.stagingWriter.isShared() { wg.Wait() } @@ -467,17 +500,14 @@ func (c *CatchpointCatchupAccessorImpl) processStagingBalances(ctx context.Conte } } if hasCreatables { - errCreatables = wdb.Atomic(func(ctx context.Context, tx *sql.Tx) error { - start := time.Now() - err := writeCatchpointStagingCreatable(ctx, tx, normalizedAccountBalances) - durCreatables = time.Since(start) - return err - }) + start := time.Now() + errCreatables = c.stagingWriter.writeCreatables(ctx, normalizedAccountBalances) + durCreatables = time.Since(start) } }() // on a in-memory database, wait for the writer to finish before starting the new writer - if wdb.IsSharedCacheConnection() { + if c.stagingWriter.isShared() { wg.Wait() } @@ -485,12 +515,9 @@ func (c *CatchpointCatchupAccessorImpl) processStagingBalances(ctx context.Conte wg.Add(1) go func() { defer wg.Done() - errHashes = wdb.Atomic(func(ctx context.Context, tx *sql.Tx) error { - start := time.Now() - err := writeCatchpointStagingHashes(ctx, tx, normalizedAccountBalances) - durHashes = time.Since(start) - return err - }) + start := time.Now() + errHashes = c.stagingWriter.writeHashes(ctx, normalizedAccountBalances) + durHashes = time.Since(start) }() wg.Wait() @@ -510,10 +537,12 @@ func (c *CatchpointCatchupAccessorImpl) processStagingBalances(ctx context.Conte progress.HashesWriteDuration += durHashes ledgerProcessstagingbalancesMicros.AddMicrosecondsSince(start, nil) - progress.ProcessedAccounts += uint64(len(normalizedAccountBalances)) progress.ProcessedBytes += uint64(len(bytes)) for _, acctBal := range normalizedAccountBalances { progress.TotalAccountHashes += uint64(len(acctBal.accountHashes)) + if !acctBal.partialBalance { + progress.ProcessedAccounts++ + } } // not strictly required, but clean up the pointer when we're done. @@ -529,7 +558,7 @@ func (c *CatchpointCatchupAccessorImpl) processStagingBalances(ctx context.Conte } // BuildMerkleTrie would process the catchpointpendinghashes and insert all the items in it into the merkle trie -func (c *CatchpointCatchupAccessorImpl) BuildMerkleTrie(ctx context.Context, progressUpdates func(uint64)) (err error) { +func (c *catchpointCatchupAccessorImpl) BuildMerkleTrie(ctx context.Context, progressUpdates func(uint64)) (err error) { wdb := c.ledger.trackerDB().Wdb rdb := c.ledger.trackerDB().Rdb err = wdb.Atomic(func(ctx context.Context, tx *sql.Tx) (err error) { @@ -708,7 +737,7 @@ func (c *CatchpointCatchupAccessorImpl) BuildMerkleTrie(ctx context.Context, pro } // GetCatchupBlockRound returns the latest block round matching the current catchpoint -func (c *CatchpointCatchupAccessorImpl) GetCatchupBlockRound(ctx context.Context) (round basics.Round, err error) { +func (c *catchpointCatchupAccessorImpl) GetCatchupBlockRound(ctx context.Context) (round basics.Round, err error) { var iRound uint64 iRound, err = readCatchpointStateUint64(ctx, c.ledger.trackerDB().Rdb.Handle, catchpointStateCatchupBlockRound) if err != nil { @@ -718,7 +747,7 @@ func (c *CatchpointCatchupAccessorImpl) GetCatchupBlockRound(ctx context.Context } // VerifyCatchpoint verifies that the catchpoint is valid by reconstructing the label. -func (c *CatchpointCatchupAccessorImpl) VerifyCatchpoint(ctx context.Context, blk *bookkeeping.Block) (err error) { +func (c *catchpointCatchupAccessorImpl) VerifyCatchpoint(ctx context.Context, blk *bookkeeping.Block) (err error) { rdb := c.ledger.trackerDB().Rdb var balancesHash crypto.Digest var blockRound basics.Round @@ -780,7 +809,7 @@ func (c *CatchpointCatchupAccessorImpl) VerifyCatchpoint(ctx context.Context, bl // StoreBalancesRound calculates the balances round based on the first block and the associated consensus parameters, and // store that to the database -func (c *CatchpointCatchupAccessorImpl) StoreBalancesRound(ctx context.Context, blk *bookkeeping.Block) (err error) { +func (c *catchpointCatchupAccessorImpl) StoreBalancesRound(ctx context.Context, blk *bookkeeping.Block) (err error) { // calculate the balances round and store it. It *should* be identical to the one in the catchpoint file header, but we don't want to // trust the one in the catchpoint file header, so we'll calculate it ourselves. catchpointLookback := config.Consensus[blk.CurrentProtocol].CatchpointLookback @@ -803,7 +832,7 @@ func (c *CatchpointCatchupAccessorImpl) StoreBalancesRound(ctx context.Context, } // StoreFirstBlock stores a single block to the blocks database. -func (c *CatchpointCatchupAccessorImpl) StoreFirstBlock(ctx context.Context, blk *bookkeeping.Block) (err error) { +func (c *catchpointCatchupAccessorImpl) StoreFirstBlock(ctx context.Context, blk *bookkeeping.Block) (err error) { blockDbs := c.ledger.blockDB() start := time.Now() ledgerStorefirstblockCount.Inc(nil) @@ -818,7 +847,7 @@ func (c *CatchpointCatchupAccessorImpl) StoreFirstBlock(ctx context.Context, blk } // StoreBlock stores a single block to the blocks database. -func (c *CatchpointCatchupAccessorImpl) StoreBlock(ctx context.Context, blk *bookkeeping.Block) (err error) { +func (c *catchpointCatchupAccessorImpl) StoreBlock(ctx context.Context, blk *bookkeeping.Block) (err error) { blockDbs := c.ledger.blockDB() start := time.Now() ledgerCatchpointStoreblockCount.Inc(nil) @@ -833,7 +862,7 @@ func (c *CatchpointCatchupAccessorImpl) StoreBlock(ctx context.Context, blk *boo } // FinishBlocks concludes the catchup of the blocks database. -func (c *CatchpointCatchupAccessorImpl) FinishBlocks(ctx context.Context, applyChanges bool) (err error) { +func (c *catchpointCatchupAccessorImpl) FinishBlocks(ctx context.Context, applyChanges bool) (err error) { blockDbs := c.ledger.blockDB() start := time.Now() ledgerCatchpointFinishblocksCount.Inc(nil) @@ -852,7 +881,7 @@ func (c *CatchpointCatchupAccessorImpl) FinishBlocks(ctx context.Context, applyC } // EnsureFirstBlock ensure that we have a single block in the staging block table, and returns that block -func (c *CatchpointCatchupAccessorImpl) EnsureFirstBlock(ctx context.Context) (blk bookkeeping.Block, err error) { +func (c *catchpointCatchupAccessorImpl) EnsureFirstBlock(ctx context.Context) (blk bookkeeping.Block, err error) { blockDbs := c.ledger.blockDB() start := time.Now() ledgerCatchpointEnsureblock1Count.Inc(nil) @@ -869,7 +898,7 @@ func (c *CatchpointCatchupAccessorImpl) EnsureFirstBlock(ctx context.Context) (b // CompleteCatchup completes the catchpoint catchup process by switching the databases tables around // and reloading the ledger. -func (c *CatchpointCatchupAccessorImpl) CompleteCatchup(ctx context.Context) (err error) { +func (c *catchpointCatchupAccessorImpl) CompleteCatchup(ctx context.Context) (err error) { err = c.FinishBlocks(ctx, true) if err != nil { return err @@ -883,7 +912,7 @@ func (c *CatchpointCatchupAccessorImpl) CompleteCatchup(ctx context.Context) (er } // finishBalances concludes the catchup of the balances(tracker) database. -func (c *CatchpointCatchupAccessorImpl) finishBalances(ctx context.Context) (err error) { +func (c *catchpointCatchupAccessorImpl) finishBalances(ctx context.Context) (err error) { wdb := c.ledger.trackerDB().Wdb start := time.Now() ledgerCatchpointFinishBalsCount.Inc(nil) @@ -986,7 +1015,7 @@ func (c *CatchpointCatchupAccessorImpl) finishBalances(ctx context.Context) (err } // Ledger returns ledger instance as CatchupAccessorClientLedger interface -func (c *CatchpointCatchupAccessorImpl) Ledger() (l CatchupAccessorClientLedger) { +func (c *catchpointCatchupAccessorImpl) Ledger() (l CatchupAccessorClientLedger) { return c.ledger } diff --git a/ledger/catchupaccessor_test.go b/ledger/catchupaccessor_test.go index 50a8d9b57..1394726bd 100644 --- a/ledger/catchupaccessor_test.go +++ b/ledger/catchupaccessor_test.go @@ -20,6 +20,7 @@ import ( "context" "encoding/binary" "fmt" + "math/rand" "os" "strings" "testing" @@ -36,6 +37,8 @@ import ( "github.com/algorand/go-algorand/logging" "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" + "github.com/algorand/go-algorand/util/db" + "github.com/algorand/msgp/msgp" ) func createTestingEncodedChunks(accountsCount uint64) (encodedAccountChunks [][]byte, last64KIndex int) { @@ -419,6 +422,145 @@ func TestCatchupAccessorResourceCountMismatch(t *testing.T) { encodedAccounts := protocol.Encode(&balances) // expect error since there is a resource count mismatch - err = catchpointAccessor.ProgressStagingBalances(context.Background(), "balances.XX.msgpack", encodedAccounts, &progress) + err = catchpointAccessor.ProgressStagingBalances(ctx, "balances.XX.msgpack", encodedAccounts, &progress) require.Error(t, err) } + +type testStagingWriter struct { + t *testing.T + hashes map[[4 + crypto.DigestSize]byte]int +} + +func (w *testStagingWriter) writeBalances(ctx context.Context, balances []normalizedAccountBalance) error { + return nil +} + +func (w *testStagingWriter) writeCreatables(ctx context.Context, balances []normalizedAccountBalance) error { + return nil +} + +func (w *testStagingWriter) writeHashes(ctx context.Context, balances []normalizedAccountBalance) error { + for _, bal := range balances { + for _, hash := range bal.accountHashes { + var key [4 + crypto.DigestSize]byte + require.Len(w.t, hash, 4+crypto.DigestSize) + copy(key[:], hash) + w.hashes[key] = w.hashes[key] + 1 + } + } + return nil +} + +func (w *testStagingWriter) isShared() bool { + return false +} + +// makeTestCatchpointCatchupAccessor creates a CatchpointCatchupAccessor given a ledger +func makeTestCatchpointCatchupAccessor(ledger *Ledger, log logging.Logger, writer stagingWriter) *catchpointCatchupAccessorImpl { + return &catchpointCatchupAccessorImpl{ + ledger: ledger, + stagingWriter: writer, + log: log, + } +} + +func TestCatchupAccessorProcessStagingBalances(t *testing.T) { + partitiontest.PartitionTest(t) + + log := logging.TestingLog(t) + writer := &testStagingWriter{t: t, hashes: make(map[[4 + crypto.DigestSize]byte]int)} + l := Ledger{ + log: log, + genesisProto: config.Consensus[protocol.ConsensusCurrentVersion], + synchronousMode: db.SynchronousMode(100), // non-existing in order to skip the underlying db call in ledger.setSynchronousMode + } + catchpointAccessor := makeTestCatchpointCatchupAccessor(&l, log, writer) + + randomSimpleBaseAcct := func() baseAccountData { + accountData := baseAccountData{ + RewardsBase: crypto.RandUint63(), + MicroAlgos: basics.MicroAlgos{Raw: crypto.RandUint63()}, + AuthAddr: ledgertesting.RandomAddress(), + } + return accountData + } + + encodedBalanceRecordFromBase := func(addr basics.Address, base baseAccountData, resources map[uint64]msgp.Raw, more bool) encodedBalanceRecordV6 { + ebr := encodedBalanceRecordV6{ + Address: addr, + AccountData: protocol.Encode(&base), + Resources: resources, + ExpectingMoreEntries: more, + } + return ebr + } + + const numAccounts = 5 + const acctXNumRes = 13 + const expectHashes = numAccounts + acctXNumRes + progress := CatchpointCatchupAccessorProgress{ + TotalAccounts: numAccounts, + TotalChunks: 2, + SeenHeader: true, + Version: CatchpointFileVersionV6, + } + + // create some walking gentlemen + acctA := randomSimpleBaseAcct() + acctB := randomSimpleBaseAcct() + acctC := randomSimpleBaseAcct() + acctD := randomSimpleBaseAcct() + + // prepare chunked account + addrX := ledgertesting.RandomAddress() + acctX := randomSimpleBaseAcct() + acctX.TotalAssets = acctXNumRes + acctXRes1 := make(map[uint64]msgp.Raw, acctXNumRes/2+1) + acctXRes2 := make(map[uint64]msgp.Raw, acctXNumRes/2) + emptyRes := resourcesData{ResourceFlags: resourceFlagsEmptyAsset} + emptyResEnc := protocol.Encode(&emptyRes) + for i := 0; i < acctXNumRes; i++ { + if i <= acctXNumRes/2 { + acctXRes1[rand.Uint64()] = emptyResEnc + } else { + acctXRes2[rand.Uint64()] = emptyResEnc + } + } + + // make chunks + chunks := []catchpointFileBalancesChunkV6{ + { + Balances: []encodedBalanceRecordV6{ + encodedBalanceRecordFromBase(ledgertesting.RandomAddress(), acctA, nil, false), + encodedBalanceRecordFromBase(ledgertesting.RandomAddress(), acctB, nil, false), + encodedBalanceRecordFromBase(addrX, acctX, acctXRes1, true), + }, + }, + { + Balances: []encodedBalanceRecordV6{ + encodedBalanceRecordFromBase(addrX, acctX, acctXRes2, false), + encodedBalanceRecordFromBase(ledgertesting.RandomAddress(), acctC, nil, false), + encodedBalanceRecordFromBase(ledgertesting.RandomAddress(), acctD, nil, false), + }, + }, + } + + // process chunks + ctx := context.Background() + progress.SeenHeader = true + for _, chunk := range chunks { + blob := protocol.Encode(&chunk) + err := catchpointAccessor.processStagingBalances(ctx, blob, &progress) + require.NoError(t, err) + } + + // compare account counts and hashes + require.Equal(t, progress.TotalAccounts, progress.ProcessedAccounts) + + // ensure no duplicate hashes + require.Equal(t, uint64(expectHashes), progress.TotalAccountHashes) + require.Equal(t, expectHashes, len(writer.hashes)) + for _, count := range writer.hashes { + require.Equal(t, 1, count) + } +} diff --git a/libgoal/libgoal.go b/libgoal/libgoal.go index 3ec8cd45c..a7cdde4ea 100644 --- a/libgoal/libgoal.go +++ b/libgoal/libgoal.go @@ -55,13 +55,11 @@ const DefaultKMDDataDir = nodecontrol.DefaultKMDDataDir // Client represents the entry point for all libgoal functions type Client struct { - nc nodecontrol.NodeController - kmdStartArgs nodecontrol.KMDStartArgs - dataDir string - cacheDir string - consensus config.ConsensusProtocols - algodVersionAffinity algodclient.APIVersion - kmdVersionAffinity kmdclient.APIVersion + nc nodecontrol.NodeController + kmdStartArgs nodecontrol.KMDStartArgs + dataDir string + cacheDir string + consensus config.ConsensusProtocols suggestedParamsCache v1.TransactionParams suggestedParamsExpire time.Time @@ -148,8 +146,6 @@ func (c *Client) init(config ClientConfig, clientType ClientType) error { } c.dataDir = dataDir c.cacheDir = config.CacheDir - c.algodVersionAffinity = algodclient.APIVersionV1 - c.kmdVersionAffinity = kmdclient.APIVersionV1 // Get node controller nc, err := getNodeController(config.BinDir, config.AlgodDataDir) @@ -204,7 +200,6 @@ func (c *Client) ensureAlgodClient() (*algodclient.RestClient, error) { if err != nil { return nil, err } - algod.SetAPIVersionAffinity(c.algodVersionAffinity) return &algod, err } @@ -1053,12 +1048,6 @@ func (c *Client) ConsensusParams(round uint64) (consensus config.ConsensusParams return params, nil } -// SetAPIVersionAffinity sets the desired client API version affinity of the algod and kmd clients. -func (c *Client) SetAPIVersionAffinity(algodVersionAffinity algodclient.APIVersion, kmdVersionAffinity kmdclient.APIVersion) { - c.algodVersionAffinity = algodVersionAffinity - c.kmdVersionAffinity = kmdVersionAffinity -} - // AbortCatchup aborts the currently running catchup func (c *Client) AbortCatchup() error { algod, err := c.ensureAlgodClient() @@ -1066,7 +1055,6 @@ func (c *Client) AbortCatchup() error { return err } // we need to ensure we're using the v2 status so that we would get the catchpoint information. - algod.SetAPIVersionAffinity(algodclient.APIVersionV2) resp, err := algod.Status() if err != nil { return err diff --git a/shared/pingpong/accounts.go b/shared/pingpong/accounts.go index 23bb810fc..610a0e9b5 100644 --- a/shared/pingpong/accounts.go +++ b/shared/pingpong/accounts.go @@ -29,6 +29,7 @@ import ( "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" + "github.com/algorand/go-algorand/crypto/passphrase" v1 "github.com/algorand/go-algorand/daemon/algod/api/spec/v1" algodAcct "github.com/algorand/go-algorand/data/account" "github.com/algorand/go-algorand/data/basics" @@ -44,6 +45,8 @@ func deterministicAccounts(initCfg PpConfig) <-chan *crypto.SignatureSecrets { go randomDeterministicAccounts(initCfg, out) } else if initCfg.GeneratedAccountSampleMethod == "sequential" { go sequentialDeterministicAccounts(initCfg, out) + } else if initCfg.GeneratedAccountSampleMethod == "mnemonic" { + go mnemonicDeterministicAccounts(initCfg, out) } return out } @@ -51,7 +54,7 @@ func deterministicAccounts(initCfg PpConfig) <-chan *crypto.SignatureSecrets { func randomDeterministicAccounts(initCfg PpConfig, out chan *crypto.SignatureSecrets) { numAccounts := initCfg.NumPartAccounts totalAccounts := initCfg.GeneratedAccountsCount - if totalAccounts < numAccounts*4 { + if totalAccounts < uint64(numAccounts)*4 { // simpler rand strategy for smaller totalAccounts order := rand.Perm(int(totalAccounts))[:numAccounts] for _, acct := range order { @@ -86,6 +89,21 @@ func sequentialDeterministicAccounts(initCfg PpConfig, out chan *crypto.Signatur binary.LittleEndian.PutUint64(seed[:], uint64(acct)) out <- crypto.GenerateSignatureSecrets(seed) } + close(out) +} + +func mnemonicDeterministicAccounts(initCfg PpConfig, out chan *crypto.SignatureSecrets) { + for _, mnemonic := range initCfg.GeneratedAccountsMnemonics { + seedbytes, err := passphrase.MnemonicToKey(mnemonic) + if err != nil { + fmt.Fprintf(os.Stderr, "Cannot recover key seed from mnemonic: %v\n", err) + os.Exit(1) + } + var seed crypto.Seed + copy(seed[:], seedbytes) + out <- crypto.GenerateSignatureSecrets(seed) + } + close(out) } // load accounts from ${ALGORAND_DATA}/${netname}-${version}/*.rootkey diff --git a/shared/pingpong/config.go b/shared/pingpong/config.go index 5b9224c01..8e406d255 100644 --- a/shared/pingpong/config.go +++ b/shared/pingpong/config.go @@ -77,9 +77,10 @@ type PpConfig struct { // configuration related to using bootstrapped ledgers built by netgoal // TODO: support generatedAssetsCount, generatedApplicationCount DeterministicKeys bool - GeneratedAccountsCount uint32 + GeneratedAccountsCount uint64 GeneratedAccountSampleMethod string - GeneratedAccountsOffset uint32 + GeneratedAccountsOffset uint64 + GeneratedAccountsMnemonics []string WeightPayment float64 WeightAsset float64 @@ -176,6 +177,7 @@ var accountSampleMethods = []string{ "", "random", "sequential", + "mnemonic", } // Check returns an error if config is invalid. @@ -190,8 +192,9 @@ func (cfg *PpConfig) Check() error { if !sampleOk { return fmt.Errorf("unknown GeneratedAccountSampleMethod: %s", cfg.GeneratedAccountSampleMethod) } - if cfg.DeterministicKeys && (cfg.GeneratedAccountsOffset+cfg.NumPartAccounts > cfg.GeneratedAccountsCount) { + if cfg.DeterministicKeys && (cfg.GeneratedAccountsOffset+uint64(cfg.NumPartAccounts) > cfg.GeneratedAccountsCount) { return fmt.Errorf("(GeneratedAccountsOffset %d) + (NumPartAccounts %d) > (GeneratedAccountsCount %d)", cfg.GeneratedAccountsOffset, cfg.NumPartAccounts, cfg.GeneratedAccountsCount) } + return nil } diff --git a/test/e2e-go/features/catchup/catchpointCatchup_test.go b/test/e2e-go/features/catchup/catchpointCatchup_test.go index 99910942d..83b01b8c0 100644 --- a/test/e2e-go/features/catchup/catchpointCatchup_test.go +++ b/test/e2e-go/features/catchup/catchpointCatchup_test.go @@ -198,7 +198,6 @@ func TestBasicCatchpointCatchup(t *testing.T) { targetCatchpointRound := (basics.Round(expectedBlocksToDownload+minRound)/catchpointInterval + 1) * catchpointInterval targetRound := uint64(targetCatchpointRound) + 1 primaryNodeRestClient := fixture.GetAlgodClientForController(primaryNode) - primaryNodeRestClient.SetAPIVersionAffinity(algodclient.APIVersionV2) log.Infof("Building ledger history..") for { err = fixture.ClientWaitForRound(primaryNodeRestClient, currentRound, 45*time.Second) @@ -378,7 +377,6 @@ func TestCatchpointLabelGeneration(t *testing.T) { currentRound := uint64(1) targetRound := uint64(21) primaryNodeRestClient := fixture.GetAlgodClientForController(primaryNode) - primaryNodeRestClient.SetAPIVersionAffinity(algodclient.APIVersionV2) log.Infof("Building ledger history..") for { err = fixture.ClientWaitForRound(primaryNodeRestClient, currentRound, 45*time.Second) diff --git a/test/e2e-go/restAPI/restClient_test.go b/test/e2e-go/restAPI/restClient_test.go index 3506b8b66..1c9c94216 100644 --- a/test/e2e-go/restAPI/restClient_test.go +++ b/test/e2e-go/restAPI/restClient_test.go @@ -36,9 +36,7 @@ import ( "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/crypto/merklesignature" - algodclient "github.com/algorand/go-algorand/daemon/algod/api/client" v1 "github.com/algorand/go-algorand/daemon/algod/api/spec/v1" - kmdclient "github.com/algorand/go-algorand/daemon/kmd/client" "github.com/algorand/go-algorand/data/account" "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/data/transactions" @@ -201,7 +199,6 @@ func TestClientCanGetStatus(t *testing.T) { statusResponse, err := testClient.Status() a.NoError(err) a.NotEmpty(statusResponse) - testClient.SetAPIVersionAffinity(algodclient.APIVersionV2, kmdclient.APIVersionV1) statusResponse2, err := testClient.Status() a.NoError(err) a.NotEmpty(statusResponse2) @@ -218,7 +215,6 @@ func TestClientCanGetStatusAfterBlock(t *testing.T) { statusResponse, err := testClient.WaitForRound(1) a.NoError(err) a.NotEmpty(statusResponse) - testClient.SetAPIVersionAffinity(algodclient.APIVersionV2, kmdclient.APIVersionV1) statusResponse, err = testClient.WaitForRound(statusResponse.LastRound + 1) a.NoError(err) a.NotEmpty(statusResponse) @@ -955,8 +951,6 @@ func TestPendingTransactionInfoInnerTxnAssetCreate(t *testing.T) { testClient.WaitForRound(1) - testClient.SetAPIVersionAffinity(algodclient.APIVersionV2, kmdclient.APIVersionV1) - wh, err := testClient.GetUnencryptedWalletHandle() a.NoError(err) addresses, err := testClient.ListAddresses(wh) diff --git a/tools/debug/determaccount/main.go b/tools/debug/determaccount/main.go new file mode 100644 index 000000000..84dfbf73f --- /dev/null +++ b/tools/debug/determaccount/main.go @@ -0,0 +1,45 @@ +// Copyright (C) 2019-2022 Algorand, Inc. +// This file is part of go-algorand +// +// go-algorand is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// go-algorand is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with go-algorand. If not, see <https://www.gnu.org/licenses/>. + +package main + +import ( + "encoding/binary" + "flag" + "fmt" + "os" + + "github.com/algorand/go-algorand/crypto" + "github.com/algorand/go-algorand/data/basics" +) + +var numAccounts = flag.Uint64("numaccounts", 0, "Use this many accounts") +var offset = flag.Uint64("offset", 0, "Start at this offset") + +func main() { + flag.Parse() + if *numAccounts == 0 { + flag.Usage() + os.Exit(1) + } + for i := uint64(0); i < *numAccounts; i++ { + acct := i + *offset + var seed crypto.Seed + binary.LittleEndian.PutUint64(seed[:], uint64(acct)) + secrets := crypto.GenerateSignatureSecrets(seed) + fmt.Println(i, acct, basics.Address(secrets.SignatureVerifier).String()) + } +} |