From cebfce1720ae91e0bd18504445fb32bad0d643ef Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 30 Nov 2023 20:41:14 +0100 Subject: [PATCH 01/33] chore: add testkeyring pkg --- testutil/testkeyring/accounts.go | 129 ++++++++++++++++++ testutil/testkeyring/accounts_table.go | 111 +++++++++++++++ testutil/testkeyring/gen_accounts/gen.go | 89 ++++++++++++ testutil/testkeyring/gen_accounts/template.go | 26 ++++ testutil/testkeyring/keyring.go | 38 ++++++ 5 files changed, 393 insertions(+) create mode 100644 testutil/testkeyring/accounts.go create mode 100644 testutil/testkeyring/accounts_table.go create mode 100644 testutil/testkeyring/gen_accounts/gen.go create mode 100644 testutil/testkeyring/gen_accounts/template.go create mode 100644 testutil/testkeyring/keyring.go diff --git a/testutil/testkeyring/accounts.go b/testutil/testkeyring/accounts.go new file mode 100644 index 000000000..ad96b8bda --- /dev/null +++ b/testutil/testkeyring/accounts.go @@ -0,0 +1,129 @@ +package testkeyring + +import ( + "encoding/base64" + "encoding/json" + "sync/atomic" + + errorsmod "cosmossdk.io/errors" + "github.com/cosmos/cosmos-sdk/testutil" + sdktypes "github.com/cosmos/cosmos-sdk/types" +) + +var ( + ErrPreGeneratedAccountIndexOutOfRange = errorsmod.New(codespace, 1, "index out of range of pre-generated accounts list") + codespace = "testutil/network" +) + +type PreGeneratedAccount struct { + Address sdktypes.AccAddress + Mnemonic string +} + +type PreGeneratedAccountIterator struct { + accounts []*PreGeneratedAccount + nextIndex uint32 +} + +// PreGeneratedAccountAtIndex returns the account at the given index. It returns +// an error if the index is out of range. +func PreGeneratedAccountAtIndex(index uint32) (*PreGeneratedAccount, error) { + if preGeneratedAccounts.nextIndex >= uint32(len(preGeneratedAccounts.accounts)) { + // TODO_IN_THIS_COMMIT: refactor error... + return nil, ErrPreGeneratedAccountIndexOutOfRange.Wrapf("%d", index) + } + + return preGeneratedAccounts.accounts[index], nil +} + +// MustPreGeneratedAccountAtIndex returns the account at the given index. It +// panics on error; i.e. if the index is out of range. +func MustPreGeneratedAccountAtIndex(index uint32) *PreGeneratedAccount { + account, err := PreGeneratedAccountAtIndex(index) + if err != nil { + panic(err) + } + return account +} + +// PreGeneratedAccounts returns a new PreGeneratedAccountIterator with the +// accounts which were pre-generated by the `gen_accounts` tool. +func PreGeneratedAccounts() *PreGeneratedAccountIterator { + return preGeneratedAccounts.Clone() +} + +// NewPreGeneratedAccountIterator returns a new PreGeneratedAccountIterator with +// the given accounts. It is primarily used by the generated code to intially +// construct the preGeneratedAccounts variable. +func NewPreGeneratedAccountIterator(accounts ...*PreGeneratedAccount) *PreGeneratedAccountIterator { + return &PreGeneratedAccountIterator{ + accounts: accounts, + nextIndex: 0, + } +} + +// MustNext returns the next account in the iterator. It panics if it encounters +// an error. It is safe to call concurrently and is guaranteed to return a unique +// +// account on each call. +func (iter *PreGeneratedAccountIterator) MustNext() *PreGeneratedAccount { + next, err := iter.Next() + if err != nil { + panic(err) + } + return next +} + +// Next returns the next account in the iterator. It is safe to call +// concurrently and is guaranteed to return a unique account on each call. +func (iter *PreGeneratedAccountIterator) Next() (*PreGeneratedAccount, error) { + // NB: instead of loading and incrementing in separate steps, just increment + // and use nextIndex-1 for the current index. + nextIndex := atomic.AddUint32(&iter.nextIndex, 1) + currentIndex := nextIndex - 1 + + if currentIndex > uint32(len(iter.accounts)) { + return nil, ErrPreGeneratedAccountIndexOutOfRange.Wrapf("%d", currentIndex) + } + + return iter.accounts[currentIndex], nil +} + +// Clone returns a new PreGeneratedAccountIterator with the same accounts as the +// receiver but with its nextIndex reset to 0. +func (iter *PreGeneratedAccountIterator) Clone() *PreGeneratedAccountIterator { + return NewPreGeneratedAccountIterator(iter.accounts...) +} + +func (pga *PreGeneratedAccount) ToTestAccount(name ...string) testutil.TestAccount { + return testutil.TestAccount{ + Name: name[0], + Address: pga.Address, + } +} + +// mustParsePreGeneratedAccount parses the given base64 and JSON encoded account +// string into a PreGeneratedAccount. It panics on error. +func mustParsePreGeneratedAccount(accountStr string) *PreGeneratedAccount { + account, err := parsePreGeneratedAccount(accountStr) + if err != nil { + panic(err) + } + return account +} + +// parsePreGeneratedAccount parses the given base64 and JSON encoded account string +// into a PreGeneratedAccount. +func parsePreGeneratedAccount(accountStr string) (*PreGeneratedAccount, error) { + accountJson, err := base64.StdEncoding.DecodeString(accountStr) + if err != nil { + return nil, err + } + + preGeneratedAccount := new(PreGeneratedAccount) + if err := json.Unmarshal(accountJson, preGeneratedAccount); err != nil { + return nil, err + } + + return preGeneratedAccount, nil +} diff --git a/testutil/testkeyring/accounts_table.go b/testutil/testkeyring/accounts_table.go new file mode 100644 index 000000000..108a8c7fb --- /dev/null +++ b/testutil/testkeyring/accounts_table.go @@ -0,0 +1,111 @@ +// DO NOT EDIT. This Code is generated by gen_accounts/gen.go, +// changes will be overwritten upon regeneration. +// +// To regenerate this file, use make go_test_accountgen or go generate ./testutil/network/keyring.go. + +package testkeyring + +var ( + preGeneratedAccounts = NewPreGeneratedAccountIterator( + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWRwZzN5YWU5OWc4bHJ3Nzl3dzBrZzJ6YTg0MzY2ZDZ0NjNrdTdkIiwiTW5lbW9uaWMiOiJsaWtlIGhpcCBzd2FtcCBmb3VuZCBjcnlzdGFsIGZsYW1lIGRlY3JlYXNlIGNydXNoIGNvaW4gY29uZHVjdCBhZmZhaXIgdmlsbGFnZSBjcnVlbCBtb250aCBob3N0IGdsb2JlIHJlZnVzZSByaWdpZCBmZWJydWFyeSBvdmVuIGNvcmUgY3JvcCBpbnB1dCBndWlsdCJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTczYzI2dG05enp2MnVnbGNhdmFkMGd3dG02azd0cTN0MmtzN2s4IiwiTW5lbW9uaWMiOiJyb2JvdCBzdW5ueSBoaWxsIHNvY2NlciB0b2JhY2NvIHBhbmVsIGluY2x1ZGUgdGFibGUgaW52aXRlIHNoeSB3b3JsZCBwZXJzb24gZG9vciBwdW5jaCBzdGluZyBkZWNvcmF0ZSB3aW5rIHNjaXNzb3JzIG94eWdlbiB0aG91Z2h0IGxpZnQgZGVjbGluZSBtb29uIGxvYW4ifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTBzbTVlcDUzaGt5a2RnM3p0NHNwZ214amZ0YXJ6czh1ZjBkZXdqIiwiTW5lbW9uaWMiOiJzdG9uZSBwcmVzZW50IGdvbGQgYmFyZ2FpbiBsZWFmIHJlY2VpdmUgYmFyZ2FpbiByYXcgc2luY2Ugc2hvdmUgYWRqdXN0IGRlcHV0eSByb2NrZXQgZm9sbG93IGxhd3N1aXQgbWFuZ28gc3RhZ2UgcnVud2F5IGRvZyBiZWF1dHkgZ2FzIHNlbnNlIGRpYWdyYW0gdGFzayJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWR1bHp3Z3RnN2xkeDJ6dGgzbXNtbXB1d3phN2tsZDUyOTJkenh1IiwiTW5lbW9uaWMiOiJkb25hdGUgYWxpZW4gcGxhbmV0IGRlZXIgbWFuc2lvbiBiZWdpbiBub3RoaW5nIGd1aWx0IGdvb3NlIGNpdmlsIGdhdGUgcHJvZHVjZSBvbGQgZXJyb3IgYmVoYXZlIG1ha2UgZmx1c2ggYmFubmVyIGNyaWNrZXQgbGFrZSBoaXN0b3J5IGxhbXAgdmljdG9yeSB0dW1ibGUifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTRmODRqbGc3ZHFrNHlmNXY3bDg5cHh2a2FyczZtM2czbGRyYXM0IiwiTW5lbW9uaWMiOiJlbGRlciBncmllZiBmYXRhbCBzaXggY291c2luIHByb2JsZW0gdGlnZXIgdmFsdmUgaGVhdnkgY2hyb25pYyBkZXB0aCBnYXRoZXIgZmljdGlvbiBjaGltbmV5IGNyaXNwIGVjb2xvZ3kgbWFuc2lvbiBleGN1c2UgbGV0dGVyIGZhbGwgZXZva2UgY3Jhd2wgaWdub3JlIG9wZXJhIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWNwY25oanU0MDR6NDQ3Z2x4ZzlxdTNsN3c1ZHdzcGQ1emQ0NWhyIiwiTW5lbW9uaWMiOiJ3aGF0IGVtZXJnZSBob3NwaXRhbCBrZXkgZHV0Y2ggZXhhbXBsZSB1cG9uIGdvb2Qgbm9vZGxlIHNldHRsZSB3aXNlIGNvbm5lY3QgdGlwIGFsbCByb29mIGNvbWJpbmUgZXhwbGFpbiBjaGVzdCBsYWJlbCBsb2dpYyB3YWxrIGZvbGQgdHJheSByYWNjb29uIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTNrcm11ZGpldDNrY2xjZGVtMG5qaGdodzloMnBsZnFncmNqdnRlIiwiTW5lbW9uaWMiOiJraXdpIG9wcG9zZSBxdWVzdGlvbiBtb250aCByYW5kb20gZXh0cmEgZW1wb3dlciBiYW5hbmEgd29ydGggYXBhcnQgcmlzayBiZXR3ZWVuIGluc2FuZSByaXZhbCBkdWNrIGxlZyB0cmF2ZWwgcmVuZXcgc29jY2VyIGFkanVzdCBnb2RkZXNzIGNyb3VjaCBkaXNhZ3JlZSB0b3BpYyJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXozZ3NrdjdlNjR5MzZ2eDN6Y3M3ZDYzbnJ1bWRhZnRzNjZ1MjluIiwiTW5lbW9uaWMiOiJtb3ZlIGZsaWdodCBjb21pYyB5b3V0aCBkcmFmdCB0cnV0aCB0cmFzaCBiYXNpYyBsYXdzdWl0IHdpbGQgcHJpZGUgdGlzc3VlIGFwYXJ0IGluaGFsZSB6ZWJyYSBmdWVsIHRyZWF0IGhvdXIgcGhvdG8gdG9zcyB2aXNpdCB0b3AgYWxsZXkgc3R1bWJsZSJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTh1eHV2djA0MmUzbjd5d3FzMmZmODNzaDM2YzdkOXhuOGx1NmsyIiwiTW5lbW9uaWMiOiJ3b3J0aCBjaGlja2VuIGFybW9yIGNhbG0gaGVuIHRvaWxldCBldm9rZSByb3V0ZSBwYXRjaCBmYW1lIHBvcnRpb24gaG9iYnkgZXhjZXNzIG1hbmRhdGUgd29ybGQgdW5oYXBweSBoYXJkIG1vbSBvbHltcGljIGNyeXN0YWwgb2ZmaWNlIHJlbGllZiBmYXNoaW9uIHN1Y2gifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWtqcGRneG0waHN5YWhxcTQ5NHVocGt3d2w4cXZ5N3JudG12OGxoIiwiTW5lbW9uaWMiOiJva2F5IHBvZW0gYm9vc3QgYmxlYWsgc3F1ZWV6ZSBwaXBlIHRvb2wgZmlsdGVyIHRpbWJlciBzbGFiIGdhaW4gcGVvcGxlIG5ldCBhcnJlc3Qgc2VjdXJpdHkgZGVjYWRlIGNyYWZ0IGFwcGVhciBzbW9rZSBib2R5IGFzc2F1bHQgYmVhY2ggZXhvdGljIGFsdGVyIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXVudXJnd3Zna2s1NmwzM2d3bjA3MjM3NTkwODluOGU0ajRweXJmIiwiTW5lbW9uaWMiOiJ1cmJhbiBicm9jY29saSBncml0IG1lcnJ5IHJvbWFuY2UgbXl0aCBqb2IgZm9jdXMgY2xpY2sgc2h5IHByaW9yaXR5IGFzc2V0IGJyaXNrIHJlY29yZCByZW5ldyB0aW1iZXIgc3RlYWsgZmF0IGd1YXJkIG1vdGhlciBoYW5kIG5vdmVsIGN1cnZlIGxhdmEifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTY1ejRqc3Nncjl5dXNuZXNwdjd2YXk1bjcyNmNoMnYwdHF6dTU1IiwiTW5lbW9uaWMiOiJ0dW5uZWwgaHVtb3IgbWltaWMgZ2F0ZSBwaWxsIGJyZWFkIHRpbnkgc21vb3RoIHRvcGljIHdpc2UgdHdpY2Ugc3VnZ2VzdCBzb3VsIGxpbWl0IGluY3JlYXNlIGFyZWEgb3JhbmdlIHNoZXJpZmYgcHVyc2UgaW5jb21lIGphZ3VhciB3aWZlIG9yZGluYXJ5IHZpb2xpbiJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMW12cHl1OTV6bndscnprdDV0ZTdhZXMyeXN5eGhmZHptN3hlbWVsIiwiTW5lbW9uaWMiOiJsYXJnZSBiYW5hbmEgZ3JhcGUgbW9ua2V5IHVwcGVyIGdpYW50IGFjdGlvbiBtdXR1YWwgdGhlb3J5IGJlbmVmaXQgaW5kaWNhdGUgdGF0dG9vIHVwZ3JhZGUgb3BlcmEgY2hhb3MgcGFyYWRlIHNvbWVvbmUgZWR1Y2F0ZSBoYW5kIG5vYmxlIGpva2UgcmViZWwgcmFjY29vbiBhcm0ifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTcwbmFrYTVnd2swOG5xdzVqYXZtZ3A3c3VnMzUwMHMyM242ZzZmIiwiTW5lbW9uaWMiOiJlbGRlciByYXRlIGJ1c2luZXNzIGdvYXQgdGFuayBtYXR0ZXIgdXBncmFkZSByaW5nIHNob3ZlIGVjb25vbXkgYXJ0aXN0IGJhY2hlbG9yIGZsYXZvciBicmlzayBmYW1pbHkgdGVuIGJ1ZGR5IHJvYm90IHJlcXVpcmUgYWRhcHQgc3VjaCBzYWQgc2libGluZyBwaXN0b2wifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTlxcW5yNWE1M2R2azBodGgyNGRobjVhYXMwdm53bHpwbnZyNm1oIiwiTW5lbW9uaWMiOiJrYW5nYXJvbyBsaWNlbnNlIGdvb2Qgb3ZlciBxdWVzdGlvbiBzY3JhcCBhY3Jvc3MgZGVjb3JhdGUgZnJlc2ggaGFtbWVyIG1lcmdlIGNvbmZpcm0gZm9sZCB1bmFibGUgY3JhbSBzcXVlZXplIHN1cHBseSBiaXJ0aCBob3JzZSBkZXRhaWwgd2F2ZSBsaW1pdCBpbmNsdWRlIGhhaXIifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTJnN2Z6OWV2YWE4OGd2Nm1nNHA3dmM3Y2hzaGh3Nmg1NmRyM25lIiwiTW5lbW9uaWMiOiJ3aWRlIGJhdHRsZSBsZW9wYXJkIGxlbmQgcmFpbCBkaXZlcnQgZm9nIG9ycGhhbiBvY2VhbiBlbmZvcmNlIHRydWUgY29tcGFueSBkcmF3IGVuam95IHRoYXQgY29yYWwgYmxvdXNlIGZyb250IHNwb25zb3IgY29udHJvbCBjb2xvciB0b3JuYWRvIHBpbmsgYWRhcHQifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTZ3cXgwNHJqdmEzdjh4NWYzdnZtbXlwOW1mOHkzajJ1bDk3NmZhIiwiTW5lbW9uaWMiOiJncmllZiBhY3R1YWwgaW5wdXQgYmVsdCBicmFpbiB3aW5nIGp1bmsgeW91bmcgZ2VuaXVzIHBhcmsgY2lnYXIgaHVyZGxlIGxlYWRlciBkZWNlbWJlciB0d2VsdmUgbWl4dHVyZSBjb252aW5jZSB1bmZhaXIgZmxhZyBzY3JpcHQgY2hhb3Mgc3dvcmQgbWlkZGxlIGplbGx5In0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWFjMm52eHZ4aHhkaDlrc3U1M2VxdzQzMzg3emM0ajNjNHhrdW52IiwiTW5lbW9uaWMiOiJhbWF6aW5nIGh1bmdyeSBkdXN0IGVycm9yIHNjcnViIG1vcmFsIHdhdGVyIG9idGFpbiBib251cyBwdW5jaCBjbGVyayBicm9jY29saSBwcm91ZCBqdXN0IGNydWlzZSB0dXJrZXkgaWRsZSB0dW5uZWwgc2FsYWQgd2luZG93IHJlbnQgc3RvdmUgc2hhbGxvdyBydWcifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXN2eXQ4OGtrYXNkM213ZnhmcWFnbnk0c21oeHA5a2g0Y2FncjAwIiwiTW5lbW9uaWMiOiJyZWFkeSBsaXF1aWQgbW9ua2V5IGluZG9vciBjYWJiYWdlIHRyb3BoeSBidXJkZW4gcGxheSBhbmdsZSByZXZpZXcgdW5sb2NrIGhhaXIgcGFyZW50IGhhcmQgaGFsZiBuZWdhdGl2ZSBwZXJtaXQgcmVndWxhciB0cmFkZSBmcm9zdCBsYWR5IGZ1cnkgcmVndWxhciBzcXVhcmUifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXZocWNobTlkNnBybWU1enFsdHlzODYwZ3I3YWNka2RodGtnNnJhIiwiTW5lbW9uaWMiOiJpbnF1aXJ5IGxpYXIgaW1pdGF0ZSBzY2FuIHByZXBhcmUgc3RhdGUgZmluZSBjdXJyZW50IHZpcnVzIHBheW1lbnQgc2hvdmUgbm9ybWFsIGRvdWJsZSB2YXVsdCB0cmF5IGhlYWx0aCByZXNwb25zZSB3YXZlIHJlbmRlciByaXZlciBmbGF0IHNraXJ0IGxlY3R1cmUgdGVuYW50In0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWxkcTVrbHhjNmw1cjl5Mnc2NXJ2OGdrbmV4YXNkbjBmZzJwemxtIiwiTW5lbW9uaWMiOiJhZGQgaG9ja2V5IGJvb3N0IGNoYXQgc2lsZW50IGVyb2RlIGZsYW1lIGJhdHRsZSBwdXp6bGUgcm91Z2ggc2VjdGlvbiBiZWVmIGxpZ2h0IGZpbmQgcm91dGUgcmFiYml0IHZvaWQgYXJtZWQgbW9yYWwgcmlvdCBjaGFtcGlvbiBkcmlsbCBoYXphcmQgYm9vc3QifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWR0ZTA4aHNueWowcmt6em1mcnk4ZXplYWFkcGVkeHQ3eTg1N3c2IiwiTW5lbW9uaWMiOiJoaWRkZW4gc3BhcmUgbW90aW9uIG5pZ2h0IGZhdCB0ZW4gb2J2aW91cyBwdXp6bGUgYWRkcmVzcyBtZWxvZHkgamFja2V0IGVsc2UgaW5mbGljdCBhYmlsaXR5IGtleSB2YWxsZXkgZHJlc3MgcG93ZXIgbXVzaWMgYXdmdWwgc29vbiB1bmRlciBzb3VsIGFybW9yIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTM4dnIwY3hqcHhsbGs1YXVhdWM0Z3V3eGxseWd0MzczOG1jcTBwIiwiTW5lbW9uaWMiOiJ0cmFwIGNvdXNpbiBzaGFsbG93IGZpcnN0IHJveWFsIHRvZ2V0aGVyIHZpYWJsZSBiYW1ib28gYm9tYiBvY3RvYmVyIHZhY2FudCBjYW1wIGZyYW1lIGRpc2FncmVlIGN1cCBjaHVja2xlIHN5bWJvbCBtYXRlcmlhbCBhdWd1c3QgYmVzdCBtYW5hZ2Ugcm9vZiBmbGF2b3IgaW5zaWRlIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXIwcDB4eTA3dXhmNngzcDNrZ25yeGN3bjdjNjczY3hlZzJtc240IiwiTW5lbW9uaWMiOiJpZ25vcmUgdG9hc3QgcmluZyBob21lIGFoZWFkIGRlY2VtYmVyIGJpY3ljbGUgbW91c2UgZ2VudGxlIGZsb2F0IG5hbWUgZW1iYXJrIGxhcmdlIGNodXJuIGVtYnJhY2Ugc3dhbXAgZnVybmFjZSBjcmFkbGUgcHVwcHkgYW5jaWVudCBub3NlIGRlc3Ryb3kgb3JkZXIgdmVoaWNsZSJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMW13MjlueXVndWFsNjd5d3E5c2N1NGMzNXZuaHdtcG1zampwNW5hIiwiTW5lbW9uaWMiOiJkYW5nZXIgd2ViIGxlbmQgZXJhc2UgaWdub3JlIHRyYWZmaWMgZGV2b3RlIGtuaWZlIGRvY3VtZW50IHNsZWVwIGludm9sdmUgdHJpcCB3aW5lIHNvbmcgZmVhdHVyZSBtYXJpbmUgbWlzZXJ5IGFyZWEgY2FuZHkgcmFkYXIgYm9tYiBkZXN0cm95IHJlbWVtYmVyIHNpdHVhdGUifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWs3dzNkbWdrdG1oc3kwa2xoeTlhazBqcjQ1ajdoMzNra3B5anZ4IiwiTW5lbW9uaWMiOiJtZW50aW9uIGp1bXAgaWRlbnRpZnkgY2FwaXRhbCBtZW51IGNvcm4gY2FuY2VsIHJvYWQgZXF1aXAgZW5kb3JzZSB3aW4gYnVyZGVuIGZvc3RlciBsb3ZlIGNsZXJrIHByb2R1Y2UgZ3JlYXQgdGhlcmUgZ2FsYXh5IGRvbmtleSBzZW50ZW5jZSB0cnVjayBqb3VybmV5IHJvdXRlIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWQ2cWpqZTlzc3c0cTN6dzkzM3g5OXhkZTZrMzQ4bmx6cHcybThoIiwiTW5lbW9uaWMiOiJjeWNsZSBzdHVtYmxlIGRheSByZXNpc3QgYnVpbGQgY290dG9uIHZlcmIgcG93ZGVyIGFjY291bnQgdml0YWwgdmlicmFudCBzaW1pbGFyIGZhbWlseSBhZmZvcmQgc2FtZSBtdXR1YWwgcGVsaWNhbiBiYW5hbmEgYnJvdGhlciByb3VnaCBiYXJlbHkgaXNsYW5kIGF3ZXNvbWUgbHVuYXIifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMW5xcWZmd2xnZ3YyZzR3dWFzenU1M3QycWZjd3E5cHZlNHBtdTRjIiwiTW5lbW9uaWMiOiJwYXRpZW50IHNtYWxsIG11dHVhbCBhcmVuYSBmZXcgYm91bmNlIHRvbmUgYXV0aG9yIGJyb29tIGx5cmljcyBiZWdpbiByZXBhaXIgbWV0aG9kIGJyb256ZSBob3RlbCBwbGF0ZSB3aW50ZXIgZHdhcmYgaGFyYm9yIGNhZ2Ugc3Rvb2wgc25pZmYgc29hcCBleGNsdWRlIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWprMHVyaGRsYWF0enJwZjJzY3l3MmhjeHN5eGVyeHAyazV5ODlnIiwiTW5lbW9uaWMiOiJtaW5kIG1hbmRhdGUgYXNzYXVsdCB0ZXJtIGdsb29tIGJsYWRlIGNodXJuIHZlcmlmeSBicmlkZ2UgZ3JhbnQgYWhlYWQgZGljZSBqZWFucyBib3kgcGljdHVyZSBiaXJ0aCBleHBlY3QgaHVycnkgc2NhbGUgb2JzZXJ2ZSB0aHJlZSBhbG9uZSBtaXggdmVsdmV0In0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXd5d3Y5OTh5emxqcXZmNzNkMGVncm5qejVzdTZubGh1enFrM3plIiwiTW5lbW9uaWMiOiJ0dXJuIGVuZm9yY2UgZmFjZSBtdWNoIHV0aWxpdHkgcGF0aWVudCBhcnQgYnJvd24gYm94IHVwc2V0IGxhYm9yIGVuZG9yc2UgdGFnIGVhcnRoIG9mZmljZSBsb3VuZ2UgZGl2b3JjZSBiYXNlIGdsYXJlIGx1bWJlciB0b2UgdG93biBwaXRjaCBzaXN0ZXIifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXBoeXhnaGN4NGZ5bnZydDR5NG52eW5kenhoMGRyOWZ4N3NrNXA3IiwiTW5lbW9uaWMiOiJyaXZhbCB0d28gbWFyZ2luIGh1bnQgYnVkZ2V0IHdhaXQgdHJpYmUgc3VubnkgcGlnZW9uIHB1bHAgc2hvb3QgdHJlYXQga2V5IGRpc2FncmVlIHVtYnJlbGxhIG9yaWVudCBuYXR1cmUgdG9tb3Jyb3cgbGVjdHVyZSBsb2dpYyByYW5jaCBzaGFmdCBmb3NzaWwgY2FuY2VsIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMW5kejRsNHN1OWRjcWVxcjd1eDR3enJzY3c0dmVoZ2hxNXo4cnBoIiwiTW5lbW9uaWMiOiJ0aW1iZXIgdGVuYW50IHNpbmcgbHVuY2ggc2VlZCBiZWx0IGxldHRlciBydWxlIHNjYXR0ZXIgZmFsc2Ugcm90YXRlIGl0ZW0gY2xldmVyIHNsaWdodCBmaWx0ZXIgZmVlIHRyeSBibG9zc29tIGZsb2NrIGdyZWVuIHVudXN1YWwgbmV0IHNuYXAgYXdmdWwifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWd5dGt5aDJoZHk0YzNqNzJxZGRrMjNjNmNsenV4emszMHRlY3ByIiwiTW5lbW9uaWMiOiJoYXZlIGxhbmd1YWdlIGhvcGUgY2hvaWNlIGZlZGVyYWwgYmljeWNsZSBxdWl0IGFsbGV5IHBhcmsgcGxlZGdlIHJlcG9ydCBhbm51YWwgc2hydWcgaG9yc2UgYWNjZXNzIGZvcnVtIGJsdWUgc29mdCBtaWRuaWdodCBsYXRpbiB3aWZlIGh1cnJ5IGVyb3Npb24gc2VnbWVudCJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTVxeXdzOGx2eWRrandsN2VtM2c2ODVjcXZzMGU4amE5NmNjdXRkIiwiTW5lbW9uaWMiOiJub3RhYmxlIGlsbCBkcmFtYSBsdW5jaCBmb3JjZSBib21iIG1hcmdpbiBpZGxlIGZpbmUgdGFzdGUgZGlzaCBub3RhYmxlIHB1c2ggZXhpdCBhaXJwb3J0IGNhc2lubyBzY2hvb2wgY2FnZSBzdHVtYmxlIHRvd24ga2lkIHN1cHJlbWUgYWxhcm0gdGhleSJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWN0NDV6a3RnNDd2a3I3a3lyNmVlNG54eWdndzU1c3R4c3ZkN2E5IiwiTW5lbW9uaWMiOiJldmlkZW5jZSBqb2luIHJhdGUgdW5rbm93biBzcG90IHNob2Ugd2hpc3BlciBzZWVkIGNpdmlsIG1haWQgbmVydmUgZG9ub3IgYmFsY29ueSBjcm91Y2ggc29jY2VyIG9rYXkgb2ZmZXIgamVsbHkgYWdlbnQgY3Jhd2wgY2FudmFzIGVsZGVyIHNhbmQgZGF1Z2h0ZXIifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXh5bGEzbjNtY2RnOGdmbHJ4dmR3cG1ycDlhYWQ1eGZmcTY4eDY3IiwiTW5lbW9uaWMiOiJzb29uIGdvc3BlbCBmcmFnaWxlIHNhbG1vbiBnb29kIGVjaG8gcGFycm90IGRpbGVtbWEgc3BhcmUgZmF0aWd1ZSB0d2luIGVzY2FwZSBwYW50aGVyIHRyaXAgZXh0ZW5kIGVuYWN0IGJlYW4gbGVnYWwgYmlydGggY29uZmlybSBlbXBsb3kgY29sbGVjdCBtZWRhbCB2aXRhbCJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXNrN2N1YWhxemd2aGRqdWE5djZhcW43eHBkc2c5azVqcWw2ZGx2IiwiTW5lbW9uaWMiOiJwcmlzb24gY2VudHVyeSBwdWRkaW5nIGZyaW5nZSBwcm9maXQgYWxwaGEgZGV2aWNlIGxvY2sgZW1wdHkgYWJvdXQgY3J5IG96b25lIGZlYXR1cmUgdmlvbGluIHlvdXRoIGRlY2lkZSByYXZlbiBkaXNwbGF5IHRhbGVudCB1c2FnZSBsb25lbHkgaGludCBoYWlyIHZpbnRhZ2UifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWw4dXYydXRkZXJmNDczYW14Zno3bGw1djBlNWpnbWtqaGc5MHJyIiwiTW5lbW9uaWMiOiJ2b2lkIHNpYmxpbmcgd2FybSBmZWJydWFyeSBiaWN5Y2xlIGJlaGF2ZSBydXJhbCBjaHJvbmljIGNoZXJyeSBmYW1lIGRpc29yZGVyIHN3aXRjaCBicm93biBzYW1lIGNsaWVudCBnb29zZSBkcmlmdCB0b3NzIGFyZWEgcGVybWl0IGRlY3JlYXNlIHJpdHVhbCBpbmhhbGUgYmlydGgifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWhncXduZzM4MGdka25xdHcza2ZyOXRweXE4em5ldHVrcWdrbTBoIiwiTW5lbW9uaWMiOiJ2aWN0b3J5IHdvcnRoIHllYXIgcmVkdWNlIGxlYWRlciBleGl0IHJhcGlkIHRydWNrIHNjYW4gbWl4ZWQgbGltaXQgbWFyaW5lIGluc3BpcmUgdGVzdCB3b3J0aCByZXBhaXIgY29tbW9uIHNpbWlsYXIgZ2hvc3QgY29uZ3Jlc3Mgc2NhcmUgZmluZ2VyIGFyY3RpYyBkb3NlIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTNkcW05M2poZDI5anJqdjl6eWFxOGtteTk2d3RqcXgycDh5ZnltIiwiTW5lbW9uaWMiOiJzaG92ZSBwcm92aWRlIG1lYXN1cmUgbGVhZiBkb25vciBnb3Zlcm4gcmViZWwgcmV0aXJlIGNvcHkgb25jZSBuYXN0eSBzdWJqZWN0IHNldHRsZSBjcnkgZmF2b3JpdGUgd2VhciBkaXNtaXNzIGFzdGhtYSBrZWVwIGZpbmFsIG1vZGVsIHRyaWdnZXIgbGF0ZXIgYmFycmVsIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXBjN2x3am5rejlrZnNsdmZyOHJrOTk0amh6dmowMDIyeXpoazU1IiwiTW5lbW9uaWMiOiJzbGlnaHQgbGFiIGNyZXcgZGVmZW5zZSBjb2FjaCB1cG9uIGZhY3VsdHkgYXJlYSB3b2xmIGV4cGxhaW4gbWFudWFsIGdvcmlsbGEgbW9uc3RlciBmbGlwIGV4YWN0IGR1c3QgYmxvb2QgdG95IHBsYXRlIHNhbG1vbiBkaXJlY3QgYWdlIGJ1bGIgdG9uZSJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWY5c3IyN3Frajk4ZTJ5bXB2MHhjZDJ1Zmsyd2VqbGRsZnpmNHc3IiwiTW5lbW9uaWMiOiJjYW1wIGdhdGUgZ2lhbnQgbWFjaGluZSBwdW1wa2luIHNpYmxpbmcgaHViIHVuaWZvcm0gbGljZW5zZSB1bmRlciBjdXJ2ZSBsYW5ndWFnZSBkZXBhcnQgYXNzdW1lIGFtYXRldXIgZ3JvdyBkaWFsIG11dHVhbCByaWIgdm95YWdlIGdvZGRlc3MgY3JlZWsgYXNrIGNhc2gifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXkwOWM0cmhndDJybWxjenhld2c3eTQ4cmp4aG1qZXM2NTc3dmRzIiwiTW5lbW9uaWMiOiJweXJhbWlkIHJlbmV3IGlsbCBzdG9jayBtYXJibGUgbnV0IGdvcmlsbGEgZGlydCBleGhhdXN0IHNoYWRvdyBjb3JuIGdvc3BlbCBpbnNpZGUgbnVyc2UgZWFydGggZm9vZCBwYXRoIGJ1eWVyIHNhdG9zaGkgY3JhZGxlIHBpZ2VvbiBsZWFmIHNlYXNvbiBzY3J1YiJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTk0ZHZmN2F4ZjB4MnB1cG01ZXh0ejIyd242dWtmNGZrNWozZGhnIiwiTW5lbW9uaWMiOiJ0b3VyaXN0IHVuaWZvcm0gc2tpIHN1cnZleSBpbm5vY2VudCBvYmxpZ2UgZm9yY2UgYmVjb21lIGFjcXVpcmUgcmVtYWluIG11c2hyb29tIGJhbGNvbnkgY2hhcmdlIG1hc3RlciBjaGVlc2UgZW1wbG95IHJpZGUgYmFyIHJvYnVzdCB0aW1iZXIgc29jayB0b3VyaXN0IHVwcGVyIHJlc2lzdCJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTQ1dTV3bnZnNXlzd3hqcmx1bXhsbmpjaDJxZndyMjUyem1yZGVqIiwiTW5lbW9uaWMiOiJiZXR3ZWVuIHRyYW5zZmVyIGxpZmUgcm91Z2ggc3RvY2sgaW5oZXJpdCBvdXRlciBza2F0ZSBhbmNpZW50IHRoZXkgYmluZCBjdWJlIG92ZXIgbXlzZWxmIHJlY3ljbGUgc2Vzc2lvbiB2ZW50dXJlIGJvaWwgZW1wdHkgbG9jayBicmVhZCBleHBsYWluIGFyZ3VlIG1hZCJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWw1bHE1dTh6emc0Z2dyc2Y5ZmdxbDJsODBscjhxYWRmY3F5MGFuIiwiTW5lbW9uaWMiOiJweXJhbWlkIGd1biB2YXBvciBkZXBlbmQgcHVtcGtpbiBwZW4gY3JlZWsga2V0Y2h1cCBjYWxsIGJvb3N0IGNhcGFibGUgbmFwa2luIGF1ZGl0IGFtdXNlZCBzb2x1dGlvbiBsaXR0bGUgbWFwbGUgb2NlYW4gaGlsbCBsb29wIGxpbmsgZ2FsbGVyeSBib3ggc3RlcCJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWFkbXdkMjQzbmo0Zmo1MGZsOHcyY2hqdnZucjZqbmduMno5NHkwIiwiTW5lbW9uaWMiOiJsZWdhbCBoZWFydCBva2F5IGFpcnBvcnQgYWdlIGhlZGdlaG9nIHNsZWVwIHJlcGVhdCBhY2N1c2Ugc3ltcHRvbSBmb3N0ZXIgYmluZCBkcmlsbCBjcnVtYmxlIGVmZm9ydCBmbG9jayBtYXJibGUgY3Jvd2QgZ3J1bnQgZ3JhYiBvcmlnaW5hbCBlc3RhdGUgYWRkcmVzcyBwdXNoIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTh5eGo2M3kwdXhtM2U5dzl4ZGE0cGxodzAyZnU4MDA1M2FtenU5IiwiTW5lbW9uaWMiOiJtZW50aW9uIHBsYXkgYmF0dGxlIGxveWFsIHVuZm9sZCBmb3VuZCBjZW50dXJ5IGVuZCBjb21lIGNsdXRjaCB3YWxsIHdvb2QgZW5yaWNoIGVxdWlwIGFybW9yIGJvbnVzIGhlbiB2aWRlbyBtb3JhbCBkb2xsIGFuZ2VyIHNraXJ0IHNvZGEgc2F2ZSJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTczZHQydTdnOW1udWU4amZnamN3ZzZucXA2NjJsdTRjNm0zcHlsIiwiTW5lbW9uaWMiOiJjb25kdWN0IGludGFjdCBhaXNsZSBjaGFvcyBxdWFsaXR5IHRoZW9yeSBjaHVuayBqdWljZSBjcnVpc2UgZmVlIHJpcHBsZSBsaW1pdCBnYXVnZSBmb3Jlc3QgY2hhbmdlIHNhdXNhZ2UgZXh0cmEgYWxwaGEgdXNhZ2UgZXhvdGljIGRyaWZ0IGJyYXNzIGdvcmlsbGEgdGFzdGUifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXBsenR3Z3Qzc2c1dmszbHNtbGtsOTV1cmw1ZDR0bGd4Y3RkZGU5IiwiTW5lbW9uaWMiOiJvYmplY3QgYmFyIGNhbG0gbXl0aCBmZWUgdG9vbCBmaW5nZXIganVuZ2xlIHNpbXBsZSBiYWcgem9uZSBjaGFzZSBzY2hvb2wgYmVuY2ggYmVsdCB0aW1lIHdlYXRoZXIgZXhwcmVzcyBhZmZhaXIgc2NpZW5jZSB2ZXJiIHJlY29yZCBpbnRhY3QgZGFyaW5nIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWhsZDhrYTBxaDY3ZjJuNWV4bXplY3RlNjRhd3VkNTNkMGY3bnhhIiwiTW5lbW9uaWMiOiJob2xpZGF5IGxpdHRsZSBwb2xhciBzdWRkZW4gY29uZmlybSBzb25nIGRpYW1vbmQgcHJpZGUganVzdCBkb3ZlIG5vYmxlIGZhdm9yaXRlIGNlbnR1cnkgcnVyYWwgZmFpbnQgYWxpZW4gYWN0dWFsIGhvbGUgZHJpZnQgcG9vbCBhcnJhbmdlIGFscGhhIGJvdHRvbSBlbnRyeSJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXc2YzBleW56Zm5zd2RhNXpnOHRta3hrem1sbjNkZHY3cGd5enZ0IiwiTW5lbW9uaWMiOiJ0b25pZ2h0IGZpbGUgZGVmZW5zZSByZW5ldyBjb2lsIHVuY2xlIHBpZyBub2lzZSBibHVyIGVsc2UgZ2xvdmUgcmVtYWluIHJ1ZyBjdXJ0YWluIGNvbmZpcm0gb3JkaW5hcnkgYnVpbGQgY3J1c2ggY2FyZCBsZWF2ZSBmbGF0IGp1bmlvciBkZWJhdGUgd2F0ZXIifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWxybTB1dXM5Mzdxeng4Y3hnNXNmNWo5Z2VnanFmd3B6dHAydWd6IiwiTW5lbW9uaWMiOiJzdGF0ZSBvcmNoYXJkIGZ1biBlY29ub215IGxhZGRlciBvY2VhbiBmb3ggYm95IGN1cmlvdXMgYWxidW0gdGVzdCBzdGFpcnMgcG9ldCBlaWdodCBiZXN0IHN0cmVldCBhdXRob3Igc3Bpa2UgdGlueSBmYW4gc2F1c2FnZSBub3RhYmxlIGNydW5jaCBzaG9ydCJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTNobDdteGN0Y3QyZ2w2cDlnZTc2c2VjZDBtNG14dmp4ZGZmdWQ4IiwiTW5lbW9uaWMiOiJidWxsZXQgZ2lybCBtYXNrIHNhdXNhZ2UgdHJvdWJsZSBhZmZhaXIgcHJlc2VudCBvdmVuIGRpZXNlbCBlcm9zaW9uIHByb2dyYW0gY2hpbW5leSBsYXB0b3AgcGhvbmUgc291cmNlIGh5YnJpZCBidWJibGUgc2hpbmUgaGludCBzdXJ2ZXkgdG9ydG9pc2UgdmF1bHQgcGlhbm8gdGVuYW50In0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTI2M2ZkbjQ0dnQwcjBzeWN0MGh1NXMzeTZmeTVsYzIycWN6ZHNyIiwiTW5lbW9uaWMiOiJwYXRjaCBhbmltYWwgZGVicmlzIGltbXVuZSBhcmVhIGRvY3RvciB1dGlsaXR5IHJpYmJvbiByZXZpZXcga2l0dGVuIHByb2dyYW0gY2l0aXplbiBtb3RoZXIgYWxtb3N0IGRlZmluZSB3aGVlbCBhYm92ZSB5ZWxsb3cgdHVpdGlvbiBpZGxlIG1vcmFsIG91dGRvb3Igc3B5IHdpbGwifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTQ4a2NhamY1dzZnZW04dmE5dmhncDl5Nmxxa3JmdXN2Z3Zqc2R6IiwiTW5lbW9uaWMiOiJtYXRyaXggYnVkZ2V0IGNsYWltIHJldGlyZSBnb2xkIGluc3RhbGwgdHJhdmVsIHN0dW1ibGUgbGF0ZXIgcmVzb3VyY2UgY3Jpc3AgY2xhcmlmeSBza2F0ZSB0b3Agc3BvcnQgZ2VucmUgbWFuYWdlIHNvYXAgZnVuIHRyaWdnZXIgZmluZ2VyIGJvcmRlciByZWFkeSBmb3JjZSJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWRlY3M1bHY3OHV0a2V5aHUzc2h6N3cyaGd2MDhmOXk1dm03M2V4IiwiTW5lbW9uaWMiOiJwb29sIHNtYXJ0IGNpZ2FyIG1ldGhvZCBkaXp6eSB0YWxrIG1hbmdvIGJpbmQgd29vbCBicmFja2V0IGZpeCBlYXJseSBwZWFyIGVudmVsb3BlIGFlcm9iaWMgZXZva2UgdHJpZ2dlciBpbmNvbWUgbXlzZWxmIGhlbiBiaXJkIHBvc2l0aW9uIGhvbmV5IGFtb25nIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTJ2cXR0dmo5eDAwZW1kYXJxODk2eXJmMmFwYXN4Z3prZnJqOHJmIiwiTW5lbW9uaWMiOiJhZG1pdCB1c2FnZSBjb21wYW55IHJlY2VpdmUgcGF0dGVybiBjcnVlbCBzdW5ueSBuZWVkIGltcHJvdmUgbWlub3IgZGFuY2UgZXNzZW5jZSBzaGFsbG93IGVhcnRoIGlucXVpcnkgbm9vZGxlIGtuZWUgcmVzaXN0IGNvbWJpbmUgdm9pY2Ugc25ha2UgZGl6enkgbWFuIHBpYW5vIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWdkczR5NzRka3owY2pwdWRuZHM2MDY1Zzl4Mng4NHpxbmo2OWNjIiwiTW5lbW9uaWMiOiJ0b2RheSBxdWFydGVyIGludGFjdCBoZWFydCBtb3VzZSBncm91cCBleGN1c2UgbmVhciBmaWxtIHNob2Uga25vdyBjb21pYyB0cm9waHkgcmFpc2UgZm9zdGVyIHN1Z2dlc3QgbWF4aW11bSBvY3RvYmVyIGRpcnQgYXJteSBjdXJ0YWluIGVydXB0IGF0dGVuZCBmb2cifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTVmdHZyNWV0dXRocHN0aHJyOWN0M3I0NWFwZ3dqN2tncmM4eGRkIiwiTW5lbW9uaWMiOiJ0aGFuayBmbHkgZGl2b3JjZSBzaHJpbXAgbGFrZSBzaWxrIGd1YXJkIHN5c3RlbSBjYXJ0IGVtYnJhY2UgZWRpdCBwYXBlciB0aWx0IHJpc2sgYmV0dGVyIG1vdG9yIHRvcnRvaXNlIGFjcXVpcmUgZWNobyBmb29kIG9yZGVyIG1hbW1hbCB0d2VsdmUgdm9pY2UifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMW4wMDhycGt5aHlyZHA5c2Z2ZDYyd3p0cHhseXU0eGc5YTVnanR2IiwiTW5lbW9uaWMiOiJjYXNlIGxlc3NvbiBzdXJmYWNlIHNjaXNzb3JzIGNpdmlsIHNvcnJ5IG5lc3QgZXRoaWNzIG1lc3NhZ2UgaG9ybiBhZmZhaXIgZGVtaXNlIGJsb3Nzb20gbXVmZmluIGRyaWZ0IGZhbWUgYmluZCBzaGFyZSBtaWRkbGUgc3BvbnNvciBkZW55IHByZXBhcmUgbGlnaHQgc2hpZnQifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXhkdXc0YWFuanNteXIzZ2s4OGt2OXVjNHA4eG1lbGQzcWxsOXJxIiwiTW5lbW9uaWMiOiJydWRlIGJhc2tldCB0dXJrZXkgZWFybiBpbnNpZGUgYmVjb21lIGF3YWtlIG1vdmUgbGF5ZXIgYmFycmVsIHBlbmNpbCB1bmRvIGxhYm9yIGF2ZXJhZ2UgZHVuZSBjaGFuZ2UgYmFyZ2FpbiBwcmV0dHkgbGl0dGxlIGx1Y2t5IHN1aXQgcmVnaW9uIG1lbW9yeSBsYXp5In0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTU4NXA1ZzMyeHZ5N21weDA3eGhkeWF3NHZnZXN2YzRjZ3l5dThsIiwiTW5lbW9uaWMiOiJwYXRjaCB1bmxvY2sgdGhlcmUgY29weSBzaWxlbnQgcmVhZHkgcHVuY2ggdmVyYiBhZ2VudCBpbnZlc3QgbXl0aCByZXZlYWwgZHVuZSBsb25nIGNoaWxkIHN1bnNldCBrbmlmZSBzbWlsZSBtYWQgcm9vbSBtZXJjeSBhdWd1c3QgZ3JhY2UgcmVzb3VyY2UifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXprNWtkNXA2Z2xlOHJsdzVqZ2huaDh2aHI2ZWNuYXdqbXpucHN3IiwiTW5lbW9uaWMiOiJlY2hvIHdpc2UgY2hhdCBkb2xwaGluIGhhcHB5IG5leHQgdGltZSBmaWN0aW9uIGlkbGUgZmxhdCBwcm9maXQgYXJyb3cgZGlmZmVyIGJlaGF2ZSB0YXN0ZSBmbGlwIGNyb3AgZ2xhbmNlIGNvbmdyZXNzIGZldGNoIGNhcnBldCBzcGljZSBzdGVyZW8gZXZpZGVuY2UifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWY0MDU0azYwZjY5eXVtZnh6ZWc5dmNlbTRzeTByZWQ2cTRza2R5IiwiTW5lbW9uaWMiOiJqYXp6IG5hbWUgYmx1ZSBhbGJ1bSBhc3NldCBjaW5uYW1vbiBwZW5hbHR5IHJ1cmFsIG1hcGxlIGhlYWx0aCBzaWxseSBmbG9hdCBob3Jyb3Iga25pZmUgY2FuYWwgY3ViZSB3aGF0IHRvcHBsZSBlbXB0eSBqZWFucyBzcGhlcmUgYWdyZWUgYmxpbmQgdHJheSJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTMwcjNwNG1nOWg1Z3FnanZ5d2hyazh3MDMwOXdkZzl6MmR1Z3ByIiwiTW5lbW9uaWMiOiJjb2FjaCBzZWdtZW50IHBhcnJvdCB1cmJhbiBjbG9jayBleHByZXNzIGp1ZGdlIGRhbWFnZSB2b3lhZ2Ugd2VhciByb3VnaCBoZWFydCBsaXF1aWQgZ3J1bnQgc29jY2VyIHBvaW50IGlkbGUgdGlkZSBzYXRvc2hpIGdpcmwgYmFnIG1hY2hpbmUgaW1wb3NlIGJyb3RoZXIifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXdnNWdjZHg0ZTRoemRwenpkajNuM2hneTNqZHlkbDI1ZGFrbWVlIiwiTW5lbW9uaWMiOiJrbmVlIGNyaXRpYyBwcm92aWRlIGRvZyBvc3RyaWNoIGxhd3N1aXQgYm9uZSBzbWFydCBwcm9qZWN0IGluZGV4IGZhaW50IHNwb2lsIGRlY3JlYXNlIGV4aWxlIGNhdHRsZSBodXJ0IGJsYW5rZXQgYXJ0d29yayBkcnVtIHdhZ29uIHNvdXRoIHVwb24gb3JiaXQgcGhvbmUifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTVnZjNnZTZ5cW55cjJneHRyNHo3dXI3dnpuN3NsNzZ2NnB0NTJ1IiwiTW5lbW9uaWMiOiJjdXAgY291bnRyeSB0cnVtcGV0IGFjdCBhc3RobWEgdXBwZXIgaW5wdXQgd2FsbnV0IGZsYWcgcHJhY3RpY2Ugc3RhYmxlIGN1dGUgbWlsbGlvbiBmaWd1cmUgbGFkeSBkaXJ0IHNoYXJlIHByZXZlbnQgb2ZmIGFkanVzdCBzdGluZyB0b3JuYWRvIGd1biBqdW5nbGUifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXE4c214aDRtY3BlcDNucWE0bHMyd2p3eXlxOXo3cmdhemhxZ2c1IiwiTW5lbW9uaWMiOiJlY2hvIGJhc2UgY2FiYmFnZSBleGhpYml0IGluamVjdCBpY2UgY3JlZGl0IGhhdCBzdGVhayB3YXJmYXJlIGRlc2lnbiBqZXdlbCBjaHVuayBzdGVlbCB1bmRvIGVucmljaCBrZXRjaHVwIHNpeCB0aG91Z2h0IGplYW5zIG11c2V1bSBzZWN1cml0eSBlbGJvdyByb29mIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTk3ZHhmNzMyd3c1M2RwdXl4em4wcThjZ3d0Z3ZmeHZ1dnprZGw3IiwiTW5lbW9uaWMiOiJwaWxvdCBhYmFuZG9uIG11c3QgcmFpbiBkZXNrIGdsb3cgd29ycnkgc2VtaW5hciBncmFpbiByaHl0aG0gZGF3biBsaXF1aWQgd2lsZCBlbm91Z2ggZm9zdGVyIGVuam95IHdyZXN0bGUgZXllYnJvdyBpbnZlc3QgcmVsYXggYmFyIHByb3VkIHN1YmplY3Qgc3R1ZGVudCJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTJnOGQ2dnhnbXNybGd4bXZqeHI2Y2R6dTdqYzQ0aG11dXptNTBmIiwiTW5lbW9uaWMiOiJjbGVhbiBub21pbmVlIHByb29mIGJvbWIga2lkbmV5IHByb2JsZW0gd2lsZCBpc29sYXRlIGhhcmQgYmljeWNsZSBzdXJ2ZXkgbm93IHJlZ3VsYXIgZGlyZWN0IHN1bm55IGNvbmdyZXNzIGFibGUgam91cm5leSBwb3dkZXIgZmF1bHQgbW90aW9uIHRhY2tsZSB2aXZpZCBqb3VybmV5In0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTJsNGVzcGFsZ3NxZTk4czRzMnd4dmdhY3BhaDNyMnRxZTNneXF4IiwiTW5lbW9uaWMiOiJjbG9nIGxhYiBkb3VibGUgc2VjdGlvbiBkaXp6eSBicmFpbiBpbnRhY3QgZGV2ZWxvcCBtb2RpZnkgaGVkZ2Vob2cgdG93ZXIgc2x1c2ggY2F1Z2h0IGRpdmlkZSBzcGFjZSBsaXR0bGUgdGFzayB0ZXJtIGF0dHJhY3QgbWlkZGxlIHNoaWZ0IGNsdWIgY3VsdHVyZSBodW1hbiJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXgwYXlwYW10ZjN5bjRmbHQ2NjN2dmN0Zmd4d24yZnRucWozM2dzIiwiTW5lbW9uaWMiOiJiYWJ5IGJvcmluZyB3YWdlIHF1YWxpdHkgY2xpbmljIHNpZGUgYWZyYWlkIGtpbmQgd2FsbCBpbm5vY2VudCBzdGluZyBpZGVudGlmeSBjdWJlIG5pY2Ugc2xlZXAgcmFuZ2UgZmVlZCBjYXNpbm8gc3R1bWJsZSB1c2VmdWwgZWRpdCBob3N0IGZyb3N0IGJsaW5kIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWVtZ2ZjZWM4N3o1dXV0MnA5ZHFsYTVtNncwZ3luNzc4eHdwOTN0IiwiTW5lbW9uaWMiOiJidXJzdCBzaWNrIHR3byB0cnVtcGV0IGRyaWZ0IGJvdHRvbSBzaWJsaW5nIGNsb2NrIHllbGxvdyBtYXhpbXVtIGtpc3Mgc2hvY2sgaGVpZ2h0IHRlYWNoIHNhbHV0ZSBpZ25vcmUgY2F1dGlvbiBlYWdlciBmaW5kIGFwb2xvZ3kgc2F0b3NoaSBzcG9vbiBzYWRuZXNzIG1hdHRlciJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWh2Y3Nmc2xzZXQzcXI0ODRocGxuN3FhY2x5cnpyZXc1ejcyd3d0IiwiTW5lbW9uaWMiOiJhaXNsZSBpbnB1dCB0ZW4gZ3JlZW4gbWFuYWdlIHZpYnJhbnQgZmFtZSBidXNpbmVzcyBibGluZCByYWNjb29uIHNsaW0gdHJhaW4gYnVzaW5lc3MgZW5nYWdlIGRlc3Ryb3kgaW1wb3NlIHBsdWcgcG90YXRvIGFib3ZlIHZlc3NlbCBhdmVyYWdlIGFncmVlIHN0ZWVsIGNhdGFsb2cifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWxqNmhnaDkzamRjZ2c5NGowNWtnc3ZuYzl2OTd3c3BlcXRjNHU1IiwiTW5lbW9uaWMiOiJiYXR0bGUgYm9udXMgbnVyc2UgYWRkcmVzcyBzZWxsIHRvb3RoIGxhcmdlIGN5Y2xlIHB1ZGRpbmcgZXJhc2UgZGVwb3NpdCBtZWFkb3cgb2JzY3VyZSB0YWcgYWN0IGJhbGwgYXR0cmFjdCBjb3lvdGUgcmVwbGFjZSBpbm1hdGUgb3Bwb3NlIGFyb3VuZCByYXZlbiBwYXBlciJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXhobTVyNTRobHR2M2FzM2hna3d0cW5xdXUybXE0bXdyZ3B6anpzIiwiTW5lbW9uaWMiOiJuZWl0aGVyIGdhbGF4eSB2aXJ1cyBwbGF5IHN1biBiZWxpZXZlIG9ycGhhbiBmaW5nZXIgYnVsayBzaG9jayBsZWcgY2FwdGFpbiBicnVzaCBzcGluIG1pZG5pZ2h0IGx1Y2t5IHVnbHkgcmV1bmlvbiB3ZWVrZW5kIHdvcmQgYnVkZ2V0IHZhbiBzY3JlZW4gc2xlbmRlciJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXN4Nm5oZXNsa3RrczV3cXRlOThhYWhxbnVsZGNseG5sZ3ZtdHRtIiwiTW5lbW9uaWMiOiJjYXN0bGUgZW5nYWdlIHNoaWVsZCByb29raWUgY2hlZXNlIHB1enpsZSBiZXR3ZWVuIGZlZWQgbGlvbiBhY2N1c2UgYWhlYWQgY2FudmFzIGltYWdlIGluc3BpcmUgb21pdCBtb3JlIGNyYW5lIGRyYXN0aWMgc3Rvb2wgYmVjb21lIGhvbGUgcGx1Y2sgY29yZSB0cm9waHkifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXE3cDdlYTQ2bGZkaGU0cncycThucGM1cGh2bTJhY2x5bm0wM3R0IiwiTW5lbW9uaWMiOiJhc3N1bWUgdmFuaXNoIHVwcGVyIGdvZGRlc3MgY29taWMgd3JlY2sgdGVhY2ggd3Jpc3QgbWlzZXJ5IGd1ZXNzIHJlbnQgaGF3ayB0ZXh0IHNhbG1vbiBlcXVpcCBnZW51aW5lIGJsdXNoIHZlcmIgY29pbCByb3V0ZSB1cGdyYWRlIGJhZGdlIHN1bm55IHNwZW5kIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMW12d3loN2x0NnI5NXJseHBoN3UyMnB3OTZnemp1MDcwZHNycGd3IiwiTW5lbW9uaWMiOiJyYWJiaXQgd2F0ZXIgcGVuY2lsIHRvcm5hZG8gbmFycm93IGV4YWN0IGVuZG9yc2UgZmluZSBnaXJhZmZlIHB1cGlsIG1vbmtleSB2YWNhbnQgd2VpcmQgb2N0b2JlciB0aG91Z2h0IHN0ZWFrIGRlcGVuZCB2b2x1bWUgbmFzdHkgdG9iYWNjbyBzbGVlcCB3ZWFzZWwgYmxvb2QgdGFpbCJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWF3M2twcXV6Z2x0c2F1NTRoOWtxZGxuaG1ldjVkNmNudnM1a25rIiwiTW5lbW9uaWMiOiJwb3RhdG8gc3dhcm0geW91dGggY2FzdWFsIHVzZWxlc3MgZ2FyZGVuIGRheSBzZXR0bGUgdG9wcGxlIGZsb2NrIG9idmlvdXMgcmViZWwgYnJpY2sgdmV0ZXJhbiBnbHVlIGZyZXF1ZW50IGJlaGF2ZSBzZW50ZW5jZSBjb29sIHN1cmdlIHVuaWZvcm0gYXR0ZW5kIG1lbnUgZGV2aWNlIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXV3OGwwcHFqNGxxZGFqbnN3NHB1bTd4dHR3c3E0azNqYXh3NnZqIiwiTW5lbW9uaWMiOiJtb3JuaW5nIGZsYXQgb3duIGJhcnJlbCBmcm9nIHNpeCBpbm1hdGUgY2xvd24gcHVkZGluZyBuZWdhdGl2ZSBleG90aWMgaG9ycm9yIHNoZWxsIGNyaW1lIHJpdmFsIGJlc3QgYnJva2VuIGNsaWNrIHN1bnNldCB0YWxlbnQgY2FibGUgZW1wb3dlciBhcm1vciBoZWFkIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXU5dDdjcXJwY3R2bHB5ZGRtMnBkbHJwNm45bDA4bWVyMjd1aHQ4IiwiTW5lbW9uaWMiOiJsZXNzb24gY29yZSBkaXNhZ3JlZSBkaWFsIHNhZCBoaXJlIG1ha2UgbGF0ZXIgZW52ZWxvcGUgaG9tZSBiZWF1dHkgYmVhY2ggYWZmYWlyIHZvdGUgdHJpYWwgZnJvd24gcmF0ZSBjYXN0bGUgcmVjZWl2ZSBvY2N1ciBodW1ibGUgd2VsY29tZSB1bnZlaWwgdW5rbm93biJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXY4aHQwNThyOGM2czJlaGE2bjQyeDZueHBrZnE3cjJ3NjhnejlnIiwiTW5lbW9uaWMiOiJjb29sIGdvc3BlbCBkaXNoIG1ha2UgaGFyZCB3aXNkb20gYmVhY2ggdmlkZW8gYmFyZWx5IGNhdGNoIHNvbGFyIHN0ZXJlbyBmdW5ueSByb2FkIGFubnVhbCBib251cyBnYXRlIGFkanVzdCBsdW5jaCBmbGF0IGV4aXN0IGZldmVyIHN0cm9uZyByb3V0ZSJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMThoeWg0bnk5Nzh2bTQ3YXN4eXluM3VxeDNkOXJkaDN1aGx1a2hoIiwiTW5lbW9uaWMiOiJjYW1wIGJpZCBtYXplIG9seW1waWMgYmFsYW5jZSBzaWRlIGd1YXJkIHNwYXRpYWwgYXJyZXN0IG1lcnJ5IHBsYXkgc3VtbWVyIGdhdGUgbXVzaHJvb20gc2NpZW5jZSByaXBwbGUgcmVqZWN0IHRvcnRvaXNlIGZsb2NrIHN3YWxsb3cgcnVuIGNodWNrbGUgZWFnbGUgcmVmb3JtIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTZmZWRtOXpxMnBndnU1NXczZ2Z0NWRqcWNsa3Vubnc5NHBzZ2RlIiwiTW5lbW9uaWMiOiJ3aGFsZSBiYXJnYWluIGRpdmVydCBzb29uIGVyYXNlIGxvbmVseSBjbG90aCBidWRkeSBzY2llbmNlIHZhcG9yIG1pc3MgcXVvdGUgZml4IGxvb3AgZmllbGQgY2hlY2sgaGlzdG9yeSBwbHVjayB0b2RkbGVyIGltcHVsc2UgbWlyYWNsZSBiZWx0IHBvb2wgaW1tdW5lIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTRuMmU5bWN4dHZxN2xoeWNmZWhrc2YzYXYzMnJ2dTl5d3ZsMjcwIiwiTW5lbW9uaWMiOiJidWxiIGdhcmFnZSBhZGRpY3QgYXJjdGljIHN1YmplY3QgcmF2ZW4gdG9vbCBoZWxtZXQgY2FwYWJsZSBjb3VwbGUgYmFzZSBpbnZlc3QgYmVnaW4gY2FsbCBmYXRpZ3VlIGFsdGVyIGVhc3kgdXNlbGVzcyBnZW5pdXMgdW52ZWlsIGJlZWYga2luZ2RvbSBjb252aW5jZSBkYW5nZXIifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXlwcXk0dHN1NHUwZHhnM2d6OTdyNmtxY2dmNjg0dWN4cGptbWxhIiwiTW5lbW9uaWMiOiJsYXB0b3AgcHJvY2VzcyBub3NlIHRlYWNoIGJhcmVseSBqZXdlbCBpbml0aWFsIGF2b2NhZG8gZGlubmVyIGNoYWxrIHRyYW5zZmVyIG5lYXIgc3dpdGNoIGNhYmJhZ2UgYWJvdXQgY2hhbGsgY2hhaXIgYXNwZWN0IGd1biBsaWJlcnR5IGhvb2Qgc2VsZWN0IGJyYW5kIGthbmdhcm9vIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTByZmwwOG5heWRjZnc4cWtnNmNjdXB6YWRrdGVlZXRkMmx1NmpzIiwiTW5lbW9uaWMiOiJ0d2luIGdsYWQgc2VydmljZSBmaWd1cmUgcm9hc3QgY3JlZWsgb3lzdGVyIHB1bGwgY2xheSBhdXRvIGNsb3VkIGtldGNodXAgYm91bmNlIGZpZWxkIGdlbnRsZSBncmlkIGJyYW5kIHN0YWdlIGhlbG1ldCBzcGF0aWFsIHNwb2lsIHRleHQgY2FydCBzcHJpbmcifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTBhZTI4bDNua3FtN25saG5tczBwNnc4OHEyYWdzNWd1MHNrNjZ5IiwiTW5lbW9uaWMiOiJyZWd1bGFyIHdvb2wgb3JhbmdlIGlzbGFuZCBzaXJlbiB1bWJyZWxsYSBjcnVpc2UgYWxsZXkgdGlkZSBmbGlwIHNsYWIgdmVyaWZ5IHNob3VsZGVyIHR3aW4gbWV0YWwga2l0dGVuIGN1cGJvYXJkIGFjcXVpcmUgYWJsZSBzdXJmYWNlIHRlbGwgdW5kbyBiZXN0IGxlZ2VuZCJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWxoNWhjeG1nOWNna3Bkcm10NzZkeXJheGtwdzhndDR3aHR3ZnQ1IiwiTW5lbW9uaWMiOiJ2b2xjYW5vIGJyb256ZSBzcHJlYWQgbnVtYmVyIHdlYWx0aCBkZWZ5IGNpdGl6ZW4gd2luZSBlZmZvcnQgbmV4dCBoYW1zdGVyIGJldHRlciBsb2NrIHN5bXB0b20gaHVzYmFuZCB1bmlmb3JtIGhvdXIgdmF1bHQgcGl0Y2ggd2FzcCBzd2lmdCBpbmRpY2F0ZSBhZXJvYmljIHRvd2FyZCJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWZhNjA0bTdoa3NucXZoc2YydWpjbHFqZ3k1cDIwdXU1c3FoMHltIiwiTW5lbW9uaWMiOiJ3ZWFyIGJhbGwgaW52b2x2ZSBndWVzcyBzcG9uc29yIGVwaXNvZGUgZmljdGlvbiBjcmltZSBib3JpbmcgbWF0aCB3ZWIgc2NlbmUgYm95IGZsaWdodCBhY3RyZXNzIGltYWdlIG1hbnVhbCBxdWljayBtZWNoYW5pYyBiZWNhdXNlIGdyb3cgcnVkZSBub3JtYWwgYW50aXF1ZSJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTNwamZ1YWd3MnRlZDBhbjVhcWhtdDJsOGhrM3Q2YTk1czcyZzV5IiwiTW5lbW9uaWMiOiJzbG93IGRlZmVuc2UgZHJ5IGNyYW0gbHVtYmVyIGdpYW50IGRhdWdodGVyIG1ldGFsIGJyZWV6ZSBmb3J3YXJkIG5ldCB3b2xmIGZsYW1lIGRhbXAgcGxhY2UgdHdpc3QgZWxpdGUgcHJvb2YgZWFybHkgcG90dGVyeSBzb25nIGNveW90ZSBsaXphcmQgc29tZW9uZSJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTgwODJnZzU3dHlwd3ZxM2N0YWNhZzljcWg5ejJqZjdkbDJzeDlhIiwiTW5lbW9uaWMiOiJsb3ZlIG1lbHQgZ3JpZCBzaGFsbG93IGZhY3VsdHkgdG9zcyBzdXJyb3VuZCBpbWl0YXRlIG5lY2sgY2F0IGJhc2ljIHNsaWdodCBqYWd1YXIgYWNyb3NzIGdpdmUgYWJzZW50IHJlZ2lvbiBncmF2aXR5IGVuZG9yc2UgYnJpZ2h0IHNpbXBsZSBvY3RvYmVyIHJldW5pb24gc3RvcnkifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWxqd3Jsczg3MnB4MnEwNWFyZmdrazZnajQ0YXBxOHM1ajk5Z3Q1IiwiTW5lbW9uaWMiOiJzY291dCBtb2JpbGUgcmVjYWxsIG1lbWJlciByYWxseSB0aWx0IGNhcmQgaW50byB1bWJyZWxsYSBmZWVkIHZlcnNpb24gbm92ZWwgZ2lyYWZmZSBoYW1tZXIgem9uZSBrZWVuIG9yaWVudCBoYWxmIGRpc2FncmVlIGJlYWNoIHBvZXQgaW1wYWN0IGRpbm5lciBtYXNrIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTVzYTc4eTRkZ2tlc3oyN3k5bTZyNDByMDBzZTdtd2h5MjU2dGxoIiwiTW5lbW9uaWMiOiJnb2RkZXNzIGZpeCBjcmFuZSByaWdpZCBjYXN1YWwgd2hlYXQgc3ByYXkgY3JlYW0gY29pbiBsZWFmIGRpc3BsYXkgaHVyZGxlIGVuc3VyZSBhcm1lZCBjb3JyZWN0IGJ1bmtlciBpZGVudGlmeSBkb25hdGUgc3Bpa2UgZmFudGFzeSByZWxpZWYgZGlzYWdyZWUgZ3JhcGUgc2hvdWxkZXIifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTN6OWNteHVrdzdoaHYzNXgweDU0YXZhbXJuOXA2NWF0cGcybmR4IiwiTW5lbW9uaWMiOiJtb25zdGVyIGxhbmd1YWdlIHZvY2FsIGZseSBtYXJjaCBqb2tlIG5ldXRyYWwgamVsbHkgY2h1cm4gZ29kZGVzcyB3ZWFyIGNhbG0gdmFsaWQgbm93IGF1dHVtbiBsaWFyIHdhbnQgc3Bvb24gZ2xvb20gaGlnaCBqdXN0IHNvbWVvbmUgbWFudWFsIGVuZXJneSJ9"), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMTZjdTB4cTRyeDhlZWZqN3BrMmY5cHJmcmttejhtM3g1bWtyNjZyIiwiTW5lbW9uaWMiOiJtb3JuaW5nIG9mdGVuIGxhdGVyIGVjaG8geW91bmcgZGlsZW1tYSB1bnZlaWwgc3Vuc2V0IGdsYW5jZSBzaG9wIG9ic2VydmUgZXhwaXJlIHN0YWdlIG1lbWJlciBzaGlmdCBhY291c3RpYyBjb25maXJtIHJhZGlvIGp1ZGdlIGxhYiBtdWZmaW4gdHJpbSBnZW51aW5lIGJ1aWxkIn0="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMXQzcnVxZmN6aGp5cjRycDU5amNkdjZ4dmgwNnNhcDZuMzBjc2FhIiwiTW5lbW9uaWMiOiJsdW5jaCBib3Jyb3cgZGVmeSBwb29sIGxvY2FsIGdyYW50IHNoaXAgbXVzaHJvb20gYXdrd2FyZCBpbmNsdWRlIGtpZCBiZWx0IHBhaXIgaW50byBsZW5zIHRyYXZlbCByZWZsZWN0IHJvdXRlIG1pbmQgZW5hYmxlIG5lY2sga25lZSBzaXggd2lkdGgifQ=="), + mustParsePreGeneratedAccount("eyJBZGRyZXNzIjoiY29zbW9zMWg4MmVnOXBuN3pzM2w1bHRqdHN6ejN0MGdkNWVhejdnd3lyN2M1IiwiTW5lbW9uaWMiOiJzeXN0ZW0gdHJ5IGVhZ2VyIGNhcmQgbGVzc29uIGN1cnRhaW4gYmVjYXVzZSBmbGFtZSBpbWl0YXRlIHNpemUgc2libGluZyBsYXRlciBoaWdoIHNhbXBsZSBjbGF3IHNjYXR0ZXIgdXNlIHNlcmllcyBiYWNoZWxvciBwZXBwZXIgbmV4dCBhZ2FpbiBhbmdyeSBsb2dpYyJ9"), + ) +) diff --git a/testutil/testkeyring/gen_accounts/gen.go b/testutil/testkeyring/gen_accounts/gen.go new file mode 100644 index 000000000..7e0e72590 --- /dev/null +++ b/testutil/testkeyring/gen_accounts/gen.go @@ -0,0 +1,89 @@ +//go:build ignore + +package main + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "flag" + "fmt" + "log" + "os" + "strings" + + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/types" + + "github.com/pokt-network/poktroll/app" +) + +var ( + flagOut string + flagAccountsLimit int + defaultOutPath = "accounts_table.go" +) + +func init() { + flag.StringVar(&flagOut, "out", defaultOutPath, "the path to the generated file.") + flag.IntVar(&flagAccountsLimit, "limit", 100, "the number of accounts to generate.") +} + +func main() { + flag.Parse() + + kr := keyring.NewInMemory(app.MakeEncodingConfig().Marshaler) + + preGeneratedAccountsGobHexLines := make([]string, flagAccountsLimit) + for i := range preGeneratedAccountsGobHexLines { + record, mnemonic, err := kr.NewMnemonic( + fmt.Sprintf("key-%d", i), + keyring.English, + types.FullFundraiserPath, + keyring.DefaultBIP39Passphrase, + hd.Secp256k1, + ) + addr, err := record.GetAddress() + if err != nil { + log.Fatal(err) + } + + preGeneratedAccount := &testkeyring.PreGeneratedAccount{ + Address: addr, + Mnemonic: mnemonic, + } + + preGeneratedAccountStr, err := serializePreGeneratedAccount(preGeneratedAccount) + if err != nil { + log.Fatal(err) + } + + preGeneratedAccountsGobHexLines[i] = fmt.Sprintf(preGeneratedAccountLineFmt, preGeneratedAccountStr) + } + + newPreGeneratedAccountIteratorArgLines := strings.Join(preGeneratedAccountsGobHexLines, "\n") + outputBuffer := new(bytes.Buffer) + if err := accountsTableTemplate.Execute( + outputBuffer, + map[string]any{ + "newPreGeneratedAccountIteratorArgLines": newPreGeneratedAccountIteratorArgLines, + }, + ); err != nil { + log.Fatal(err) + } + + if err := os.WriteFile(flagOut, outputBuffer.Bytes(), 0644); err != nil { + log.Fatal(err) + } +} + +func serializePreGeneratedAccount(account *testkeyring.PreGeneratedAccount) (string, error) { + accountJson, err := json.Marshal(account) + if err != nil { + return "", err + } + + accountStr := base64.StdEncoding.EncodeToString(accountJson) + return accountStr, nil +} diff --git a/testutil/testkeyring/gen_accounts/template.go b/testutil/testkeyring/gen_accounts/template.go new file mode 100644 index 000000000..b546c0fef --- /dev/null +++ b/testutil/testkeyring/gen_accounts/template.go @@ -0,0 +1,26 @@ +//go:build ignore + +package main + +import "text/template" + +var ( + preGeneratedAccountLineFmt = "\t\tmustParsePreGeneratedAccount(%q)," + accountsTableTemplate = template.Must( + template.New("accounts_table.go").Parse( + `// DO NOT EDIT. This Code is generated by gen_accounts/gen.go, +// changes will be overwritten upon regeneration. +// +// To regenerate this file, use make go_test_accountgen or go generate ./testutil/network/keyring.go. + +package testaccounts + +var ( + preGeneratedAccounts = NewPreGeneratedAccountIterator( +{{.newPreGeneratedAccountIteratorArgLines}} + ) +) +`, + ), + ) +) diff --git a/testutil/testkeyring/keyring.go b/testutil/testkeyring/keyring.go new file mode 100644 index 000000000..73169aa1a --- /dev/null +++ b/testutil/testkeyring/keyring.go @@ -0,0 +1,38 @@ +//go:generate go run ./gen_accounts/gen.go ./gen_accounts/template.go + +package testkeyring + +import ( + "fmt" + "testing" + + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" +) + +func CreatePreGeneratedKeyringAccounts( + t *testing.T, + kr keyring.Keyring, + limit int, +) []*PreGeneratedAccount { + accounts := make([]*PreGeneratedAccount, limit) + for i := range accounts { + preGeneratedAccount := MustPreGeneratedAccountAtIndex(uint32(i)) + + uid := fmt.Sprintf("key-%d", i) + _, err := kr.NewAccount( + uid, + preGeneratedAccount.Mnemonic, + keyring.DefaultBIP39Passphrase, + types.FullFundraiserPath, + hd.Secp256k1, + ) + assert.NoError(t, err) + + accounts[i] = preGeneratedAccount + } + + return accounts +} From 586e3a4d5a34c9c142b150460e0367b7f706a8cc Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 29 Nov 2023 10:28:49 +0100 Subject: [PATCH 02/33] chore: update go.mod --- go.mod | 19 ++++++++++--------- go.sum | 41 +++++++++++++++++++++-------------------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index 2fd89fbde..c163cc87f 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 github.com/noot/ring-go v0.0.0-20231019173746-6c4b33bcf03f github.com/pokt-network/smt v0.7.1 - github.com/regen-network/gocuke v0.6.2 + github.com/regen-network/gocuke v0.6.3 github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 @@ -63,7 +63,6 @@ require ( github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect - github.com/alecthomas/participle/v2 v2.0.0-alpha7 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/aws/aws-sdk-go v1.44.203 // indirect github.com/benbjohnson/clock v1.3.5 // indirect @@ -83,7 +82,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cockroachdb/apd/v2 v2.0.2 // indirect - github.com/cockroachdb/apd/v3 v3.1.0 // indirect + github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/coinbase/rosetta-sdk-go/types v1.0.0 // indirect github.com/confio/ics23/go v0.9.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect @@ -96,8 +95,10 @@ require ( github.com/cosmos/ledger-cosmos-go v0.12.1 // indirect github.com/cosmos/rosetta-sdk-go v0.10.0 // indirect github.com/creachadair/taskgroup v0.6.1 // indirect - github.com/cucumber/common/gherkin/go/v22 v22.0.0 // indirect - github.com/cucumber/common/messages/go/v17 v17.1.1 // indirect + github.com/cucumber/common/messages/go/v19 v19.1.2 // indirect + github.com/cucumber/gherkin/go/v26 v26.2.0 // indirect + github.com/cucumber/messages/go/v21 v21.0.1 // indirect + github.com/cucumber/tag-expressions/go/v5 v5.0.6 // indirect github.com/danieljoos/wincred v1.1.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect @@ -126,7 +127,7 @@ require ( github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect - github.com/gofrs/uuid v4.3.1+incompatible // indirect + github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect github.com/golang/glog v1.1.2 // indirect @@ -134,7 +135,7 @@ require ( github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/flatbuffers v2.0.0+incompatible // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/orderedcode v0.0.1 // indirect github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect @@ -289,10 +290,10 @@ require ( google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - gotest.tools/v3 v3.5.0 // indirect + gotest.tools/v3 v3.5.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect nhooyr.io/websocket v1.8.7 // indirect - pgregory.net/rapid v0.5.5 // indirect + pgregory.net/rapid v1.1.0 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 8e4bca75c..daa6a0669 100644 --- a/go.sum +++ b/go.sum @@ -268,10 +268,6 @@ github.com/adlio/schema v1.3.3/go.mod h1:1EsRssiv9/Ce2CMzq5DoL7RiMshhuigQxrR4DMV github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= -github.com/alecthomas/participle/v2 v2.0.0-alpha7/go.mod h1:NumScqsC42o9x+dGj8/YqsIfhrIQjFEOFovxotbBirA= -github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1 h1:GDQdwm/gAcJcLAKQQZGOJ4knlw+7rfEQQcmwTbt4p5E= -github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -423,8 +419,8 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= -github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= -github.com/cockroachdb/apd/v3 v3.1.0/go.mod h1:6qgPBMXjATAdD/VefbRP9NoSLKjbB4LCoA7gN4LpHs4= +github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= +github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= @@ -492,10 +488,14 @@ github.com/creachadair/tomledit v0.0.22/go.mod h1:cIu/4x5L855oSRejIqr+WRFh+mv9g4 github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cucumber/common/gherkin/go/v22 v22.0.0 h1:4K8NqptbvdOrjL9DEea6HFjSpbdT9+Q5kgLpmmsHYl0= -github.com/cucumber/common/gherkin/go/v22 v22.0.0/go.mod h1:3mJT10B2GGn3MvVPd3FwR7m2u4tLhSRhWUqJU4KN4Fg= -github.com/cucumber/common/messages/go/v17 v17.1.1 h1:RNqopvIFyLWnKv0LfATh34SWBhXeoFTJnSrgm9cT/Ts= -github.com/cucumber/common/messages/go/v17 v17.1.1/go.mod h1:bpGxb57tDE385Rb2EohgUadLkAbhoC4IyCFi89u/JQI= +github.com/cucumber/common/messages/go/v19 v19.1.2 h1:8/ZkW9rj3KQo/regmI8kcy48tk57m427Olb7Y0lXcN4= +github.com/cucumber/common/messages/go/v19 v19.1.2/go.mod h1:0KLDvMVmmkEZcWUSKxFHSUSLS1gjujBbPN0p41IwwJ4= +github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI= +github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0= +github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI= +github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s= +github.com/cucumber/tag-expressions/go/v5 v5.0.6 h1:F0mqsu69cG/3MTTZqy+PlaPcU/MMl936OJjxKgdFgWs= +github.com/cucumber/tag-expressions/go/v5 v5.0.6/go.mod h1:/sHRc0Vt+pPjgQdNZjH8W2cnmb+tiVYp19VESzpGQsw= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/daixiang0/gci v0.4.2/go.mod h1:d0f+IJhr9loBtIq+ebwhRoTt1LGbPH96ih8bKlsRT9E= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= @@ -688,10 +688,9 @@ github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= -github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.4.1-0.20201022092350-68b0159b7869/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= @@ -782,8 +781,9 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= @@ -1685,8 +1685,8 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/regen-network/gocuke v0.6.2 h1:pHviZ0kKAq2U2hN2q3smKNxct6hS0mGByFMHGnWA97M= -github.com/regen-network/gocuke v0.6.2/go.mod h1:zYaqIHZobHyd0xOrHGPQjbhGJsuZ1oElx150u2o1xuk= +github.com/regen-network/gocuke v0.6.3 h1:RUOZJSZ4OHAKNjTCtjm090RI7/UjWCMb5kgK5QnbvfA= +github.com/regen-network/gocuke v0.6.3/go.mod h1:BowLKW4++696gTTU33teodtIhjjyaphEbhQT9D5Refw= github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= github.com/remyoudompheng/go-dbus v0.0.0-20121104212943-b7232d34b1d5/go.mod h1:+u151txRmLpwxBmpYn9z3d1sdJdjRPQpsXuYeY9jNls= @@ -1843,6 +1843,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= @@ -2868,8 +2869,8 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.2.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= -gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY= -gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -2892,8 +2893,8 @@ nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0 nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= pgregory.net/rapid v0.4.8/go.mod h1:Z5PbWqjvWR1I3UGjvboUuan4fe4ZYEYNLNQLExzCoUs= -pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= -pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= +pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= +pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= From 825d0c3ff373b6f669bd65a6965da3a9abc186df Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 29 Nov 2023 10:30:55 +0100 Subject: [PATCH 03/33] refactor: add session keeper dependency to supplier keeper --- app/app.go | 35 ++++++++++++++++++++-------- x/supplier/keeper/keeper.go | 10 +++++++- x/supplier/types/expected_keepers.go | 10 +++++++- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/app/app.go b/app/app.go index b34d4db68..8289aec0b 100644 --- a/app/app.go +++ b/app/app.go @@ -575,16 +575,6 @@ func New( ) serviceModule := servicemodule.NewAppModule(appCodec, app.ServiceKeeper, app.AccountKeeper, app.BankKeeper) - app.SupplierKeeper = *suppliermodulekeeper.NewKeeper( - appCodec, - keys[suppliermoduletypes.StoreKey], - keys[suppliermoduletypes.MemStoreKey], - app.GetSubspace(suppliermoduletypes.ModuleName), - - app.BankKeeper, - ) - supplierModule := suppliermodule.NewAppModule(appCodec, app.SupplierKeeper, app.AccountKeeper, app.BankKeeper) - app.GatewayKeeper = *gatewaymodulekeeper.NewKeeper( appCodec, keys[gatewaymoduletypes.StoreKey], @@ -607,6 +597,27 @@ func New( ) applicationModule := applicationmodule.NewAppModule(appCodec, app.ApplicationKeeper, app.AccountKeeper, app.BankKeeper) + // NB: there is a circular dependency between the supplier and session keepers. + // Because the keepers are values (as opposed to pointers), they are copied + // when passed into their respective module constructor functions. For this + // reason, the existing pattern of ignite-generated keeper/module construction + // must be broken for these keepers and modules. + // + // Order of operations: + // 1. Construct supplier keeper + // 2. Construct session keeper + // 3. Provide session keeper to supplier keeper via custom #ProvideSessionKeeper method. + // 4. Construct supplier module + // 5. Construct session module + app.SupplierKeeper = *suppliermodulekeeper.NewKeeper( + appCodec, + keys[suppliermoduletypes.StoreKey], + keys[suppliermoduletypes.MemStoreKey], + app.GetSubspace(suppliermoduletypes.ModuleName), + + app.BankKeeper, + ) + app.SessionKeeper = *sessionmodulekeeper.NewKeeper( appCodec, keys[sessionmoduletypes.StoreKey], @@ -616,6 +627,10 @@ func New( app.ApplicationKeeper, app.SupplierKeeper, ) + + app.SupplierKeeper.ProvideSessionKeeper(app.SessionKeeper) + + supplierModule := suppliermodule.NewAppModule(appCodec, app.SupplierKeeper, app.AccountKeeper, app.BankKeeper) sessionModule := sessionmodule.NewAppModule(appCodec, app.SessionKeeper, app.AccountKeeper, app.BankKeeper) // this line is used by starport scaffolding # stargate/app/keeperDefinition diff --git a/x/supplier/keeper/keeper.go b/x/supplier/keeper/keeper.go index d77218231..8e378d511 100644 --- a/x/supplier/keeper/keeper.go +++ b/x/supplier/keeper/keeper.go @@ -19,7 +19,8 @@ type ( memKey storetypes.StoreKey paramstore paramtypes.Subspace - bankKeeper types.BankKeeper + bankKeeper types.BankKeeper + sessionKeeper types.SessionKeeper } ) @@ -49,3 +50,10 @@ func NewKeeper( func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } + +// SupplySessionKeeper assigns the session keeper dependency of this supplier +// keeper. This MUST be done as a separate step from construction because there +// is a circular dependency between the supplier and session keepers. +func (k *Keeper) SupplySessionKeeper(sessionKeeper types.SessionKeeper) { + k.sessionKeeper = sessionKeeper +} diff --git a/x/supplier/types/expected_keepers.go b/x/supplier/types/expected_keepers.go index e92e7d60e..f6f8b626c 100644 --- a/x/supplier/types/expected_keepers.go +++ b/x/supplier/types/expected_keepers.go @@ -1,10 +1,14 @@ package types -//go:generate mockgen -destination ../../../testutil/supplier/mocks/expected_keepers_mock.go -package mocks . AccountKeeper,BankKeeper +//go:generate mockgen -destination ../../../testutil/supplier/mocks/expected_keepers_mock.go -package mocks . AccountKeeper,BankKeeper,SessionKeeper import ( + "context" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/types" + + sessiontypes "github.com/pokt-network/poktroll/x/session/types" ) // AccountKeeper defines the expected account keeper used for simulations (noalias) @@ -18,3 +22,7 @@ type BankKeeper interface { DelegateCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error UndelegateCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error } + +type SessionKeeper interface { + GetSession(context.Context, *sessiontypes.QueryGetSessionRequest) (*sessiontypes.QueryGetSessionResponse, error) +} From d9eb4883dc245c5e8060e1c1abbbaf17c0960af2 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 29 Nov 2023 10:31:03 +0100 Subject: [PATCH 04/33] refactor: add mock session keeper to supplier keeper testutil --- app/app.go | 4 +-- testutil/keeper/supplier.go | 51 +++++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/app/app.go b/app/app.go index 8289aec0b..dce2bca60 100644 --- a/app/app.go +++ b/app/app.go @@ -606,7 +606,7 @@ func New( // Order of operations: // 1. Construct supplier keeper // 2. Construct session keeper - // 3. Provide session keeper to supplier keeper via custom #ProvideSessionKeeper method. + // 3. Provide session keeper to supplier keeper via custom #SupplySessionKeeper method. // 4. Construct supplier module // 5. Construct session module app.SupplierKeeper = *suppliermodulekeeper.NewKeeper( @@ -628,7 +628,7 @@ func New( app.SupplierKeeper, ) - app.SupplierKeeper.ProvideSessionKeeper(app.SessionKeeper) + app.SupplierKeeper.SupplySessionKeeper(app.SessionKeeper) supplierModule := suppliermodule.NewAppModule(appCodec, app.SupplierKeeper, app.AccountKeeper, app.BankKeeper) sessionModule := sessionmodule.NewAppModule(appCodec, app.SessionKeeper, app.AccountKeeper, app.BankKeeper) diff --git a/testutil/keeper/supplier.go b/testutil/keeper/supplier.go index d54095fd6..7bca935dc 100644 --- a/testutil/keeper/supplier.go +++ b/testutil/keeper/supplier.go @@ -15,12 +15,24 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - mocks "github.com/pokt-network/poktroll/testutil/supplier/mocks" + "github.com/pokt-network/poktroll/testutil/supplier/mocks" + apptypes "github.com/pokt-network/poktroll/x/application/types" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" "github.com/pokt-network/poktroll/x/supplier/keeper" "github.com/pokt-network/poktroll/x/supplier/types" ) -func SupplierKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { +type SessionMetaFixturesByAppAddr map[string]SessionMetaFixture +type SessionMetaFixture struct { + SessionId string + AppAddr string + SupplierAddr string +} + +func SupplierKeeper(t testing.TB, sessionFixtures SessionMetaFixturesByAppAddr) (*keeper.Keeper, sdk.Context) { + t.Helper() + storeKey := sdk.NewKVStoreKey(types.StoreKey) memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey) @@ -38,6 +50,40 @@ func SupplierKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { mockBankKeeper.EXPECT().DelegateCoinsFromAccountToModule(gomock.Any(), gomock.Any(), types.ModuleName, gomock.Any()).AnyTimes() mockBankKeeper.EXPECT().UndelegateCoinsFromModuleToAccount(gomock.Any(), types.ModuleName, gomock.Any(), gomock.Any()).AnyTimes() + mockSessionKeeper := mocks.NewMockSessionKeeper(ctrl) + mockSessionKeeper.EXPECT(). + GetSession(gomock.AssignableToTypeOf(sdk.Context{}), gomock.Any()). + DoAndReturn( + func( + ctx sdk.Context, + req *sessiontypes.QueryGetSessionRequest, + ) (*sessiontypes.QueryGetSessionResponse, error) { + sessionMock, ok := sessionFixtures[req.GetApplicationAddress()] + require.Truef(t, ok, "application address not provided during mock construction: %q", req.ApplicationAddress) + + return &sessiontypes.QueryGetSessionResponse{ + Session: &sessiontypes.Session{ + Header: &sessiontypes.SessionHeader{ + ApplicationAddress: sessionMock.AppAddr, + Service: req.GetService(), + SessionStartBlockHeight: 1, + SessionId: sessionMock.SessionId, + SessionEndBlockHeight: 5, + }, + SessionId: sessionMock.SessionId, + SessionNumber: 1, + NumBlocksPerSession: 4, + Application: &apptypes.Application{ + Address: sessionMock.AppAddr, + }, + Suppliers: []*sharedtypes.Supplier{{ + Address: sessionMock.SupplierAddr, + }}, + }, + }, nil + }, + ).AnyTimes() + paramsSubspace := typesparams.NewSubspace(cdc, types.Amino, storeKey, @@ -52,6 +98,7 @@ func SupplierKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { mockBankKeeper, ) + k.SupplySessionKeeper(mockSessionKeeper) ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) From 0049e3bcd2718bd6bf3ce87e4cecca2e2777044e Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 29 Nov 2023 10:31:07 +0100 Subject: [PATCH 05/33] refactor: supplier keeper testutil usage --- x/supplier/genesis_test.go | 2 +- x/supplier/keeper/claim_test.go | 12 ++++++------ x/supplier/keeper/msg_server_stake_supplier_test.go | 6 +++--- x/supplier/keeper/msg_server_test.go | 2 +- .../keeper/msg_server_unstake_supplier_test.go | 4 ++-- x/supplier/keeper/params_test.go | 2 +- x/supplier/keeper/proof_test.go | 9 +++++---- x/supplier/keeper/query_claim_test.go | 4 ++-- x/supplier/keeper/query_params_test.go | 2 +- x/supplier/keeper/query_proof_test.go | 11 ++++++----- x/supplier/keeper/query_supplier_test.go | 4 ++-- x/supplier/keeper/supplier_test.go | 6 +++--- 12 files changed, 33 insertions(+), 31 deletions(-) diff --git a/x/supplier/genesis_test.go b/x/supplier/genesis_test.go index ba9b521f8..da9245955 100644 --- a/x/supplier/genesis_test.go +++ b/x/supplier/genesis_test.go @@ -59,7 +59,7 @@ func TestGenesis(t *testing.T) { // this line is used by starport scaffolding # genesis/test/state } - k, ctx := keepertest.SupplierKeeper(t) + k, ctx := keepertest.SupplierKeeper(t, nil) supplier.InitGenesis(ctx, *k, genesisState) got := supplier.ExportGenesis(ctx, *k) require.NotNil(t, got) diff --git a/x/supplier/keeper/claim_test.go b/x/supplier/keeper/claim_test.go index c60403a45..4e38a43d0 100644 --- a/x/supplier/keeper/claim_test.go +++ b/x/supplier/keeper/claim_test.go @@ -31,7 +31,7 @@ func createNClaims(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Claim } func TestClaim_Get(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) claims := createNClaims(keeper, ctx, 10) for _, claim := range claims { foundClaim, isClaimFound := keeper.GetClaim(ctx, @@ -46,7 +46,7 @@ func TestClaim_Get(t *testing.T) { } } func TestClaim_Remove(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) claims := createNClaims(keeper, ctx, 10) for _, claim := range claims { keeper.RemoveClaim(ctx, @@ -62,7 +62,7 @@ func TestClaim_Remove(t *testing.T) { } func TestClaim_GetAll(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) claims := createNClaims(keeper, ctx, 10) // Get all the claims and check if they match @@ -74,7 +74,7 @@ func TestClaim_GetAll(t *testing.T) { } func TestClaim_GetAll_ByAddress(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) claims := createNClaims(keeper, ctx, 10) // Get all claims for a given address @@ -86,7 +86,7 @@ func TestClaim_GetAll_ByAddress(t *testing.T) { } func TestClaim_GetAll_ByHeight(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) claims := createNClaims(keeper, ctx, 10) // Get all claims for a given ending session block height @@ -98,7 +98,7 @@ func TestClaim_GetAll_ByHeight(t *testing.T) { } func TestClaim_GetAll_BySession(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) claims := createNClaims(keeper, ctx, 10) // Get all claims for a given ending session block height diff --git a/x/supplier/keeper/msg_server_stake_supplier_test.go b/x/supplier/keeper/msg_server_stake_supplier_test.go index cd6158a81..bbc74cd6e 100644 --- a/x/supplier/keeper/msg_server_stake_supplier_test.go +++ b/x/supplier/keeper/msg_server_stake_supplier_test.go @@ -14,7 +14,7 @@ import ( ) func TestMsgServer_StakeSupplier_SuccessfulCreateAndUpdate(t *testing.T) { - k, ctx := keepertest.SupplierKeeper(t) + k, ctx := keepertest.SupplierKeeper(t, nil) srv := keeper.NewMsgServerImpl(*k) wctx := sdk.WrapSDKContext(ctx) @@ -92,7 +92,7 @@ func TestMsgServer_StakeSupplier_SuccessfulCreateAndUpdate(t *testing.T) { } func TestMsgServer_StakeSupplier_FailRestakingDueToInvalidServices(t *testing.T) { - k, ctx := keepertest.SupplierKeeper(t) + k, ctx := keepertest.SupplierKeeper(t, nil) srv := keeper.NewMsgServerImpl(*k) wctx := sdk.WrapSDKContext(ctx) @@ -173,7 +173,7 @@ func TestMsgServer_StakeSupplier_FailRestakingDueToInvalidServices(t *testing.T) } func TestMsgServer_StakeSupplier_FailLoweringStake(t *testing.T) { - k, ctx := keepertest.SupplierKeeper(t) + k, ctx := keepertest.SupplierKeeper(t, nil) srv := keeper.NewMsgServerImpl(*k) wctx := sdk.WrapSDKContext(ctx) diff --git a/x/supplier/keeper/msg_server_test.go b/x/supplier/keeper/msg_server_test.go index 7e4d01f27..b337090e3 100644 --- a/x/supplier/keeper/msg_server_test.go +++ b/x/supplier/keeper/msg_server_test.go @@ -13,7 +13,7 @@ import ( ) func setupMsgServer(t testing.TB) (types.MsgServer, context.Context) { - k, ctx := keepertest.SupplierKeeper(t) + k, ctx := keepertest.SupplierKeeper(t, nil) return keeper.NewMsgServerImpl(*k), sdk.WrapSDKContext(ctx) } diff --git a/x/supplier/keeper/msg_server_unstake_supplier_test.go b/x/supplier/keeper/msg_server_unstake_supplier_test.go index 993201971..2999a5e3c 100644 --- a/x/supplier/keeper/msg_server_unstake_supplier_test.go +++ b/x/supplier/keeper/msg_server_unstake_supplier_test.go @@ -14,7 +14,7 @@ import ( ) func TestMsgServer_UnstakeSupplier_Success(t *testing.T) { - k, ctx := keepertest.SupplierKeeper(t) + k, ctx := keepertest.SupplierKeeper(t, nil) srv := keeper.NewMsgServerImpl(*k) wctx := sdk.WrapSDKContext(ctx) @@ -68,7 +68,7 @@ func TestMsgServer_UnstakeSupplier_Success(t *testing.T) { } func TestMsgServer_UnstakeSupplier_FailIfNotStaked(t *testing.T) { - k, ctx := keepertest.SupplierKeeper(t) + k, ctx := keepertest.SupplierKeeper(t, nil) srv := keeper.NewMsgServerImpl(*k) wctx := sdk.WrapSDKContext(ctx) diff --git a/x/supplier/keeper/params_test.go b/x/supplier/keeper/params_test.go index 5a7e866fe..38f2e91b9 100644 --- a/x/supplier/keeper/params_test.go +++ b/x/supplier/keeper/params_test.go @@ -10,7 +10,7 @@ import ( ) func TestGetParams(t *testing.T) { - k, ctx := testkeeper.SupplierKeeper(t) + k, ctx := testkeeper.SupplierKeeper(t, nil) params := types.DefaultParams() k.SetParams(ctx, params) diff --git a/x/supplier/keeper/proof_test.go b/x/supplier/keeper/proof_test.go index c3fb4e753..a082a05bf 100644 --- a/x/supplier/keeper/proof_test.go +++ b/x/supplier/keeper/proof_test.go @@ -5,11 +5,12 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + keepertest "github.com/pokt-network/poktroll/testutil/keeper" "github.com/pokt-network/poktroll/testutil/nullify" "github.com/pokt-network/poktroll/x/supplier/keeper" "github.com/pokt-network/poktroll/x/supplier/types" - "github.com/stretchr/testify/require" ) // Prevent strconv unused error @@ -26,7 +27,7 @@ func createNProofs(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Proof } func TestProofGet(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) items := createNProofs(keeper, ctx, 10) for _, item := range items { rst, found := keeper.GetProof(ctx, @@ -40,7 +41,7 @@ func TestProofGet(t *testing.T) { } } func TestProofRemove(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) items := createNProofs(keeper, ctx, 10) for _, item := range items { keeper.RemoveProof(ctx, @@ -54,7 +55,7 @@ func TestProofRemove(t *testing.T) { } func TestProofGetAll(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) items := createNProofs(keeper, ctx, 10) require.ElementsMatch(t, nullify.Fill(items), diff --git a/x/supplier/keeper/query_claim_test.go b/x/supplier/keeper/query_claim_test.go index dcae244e1..1957362fa 100644 --- a/x/supplier/keeper/query_claim_test.go +++ b/x/supplier/keeper/query_claim_test.go @@ -16,7 +16,7 @@ import ( ) func TestClaim_QuerySingle(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) wctx := sdk.WrapSDKContext(ctx) claims := createNClaims(keeper, ctx, 2) tests := []struct { @@ -105,7 +105,7 @@ func TestClaim_QuerySingle(t *testing.T) { } func TestClaim_QueryPaginated(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) wctx := sdk.WrapSDKContext(ctx) claims := createNClaims(keeper, ctx, 10) diff --git a/x/supplier/keeper/query_params_test.go b/x/supplier/keeper/query_params_test.go index d9b909305..37df8b949 100644 --- a/x/supplier/keeper/query_params_test.go +++ b/x/supplier/keeper/query_params_test.go @@ -11,7 +11,7 @@ import ( ) func TestParamsQuery(t *testing.T) { - keeper, ctx := testkeeper.SupplierKeeper(t) + keeper, ctx := testkeeper.SupplierKeeper(t, nil) wctx := sdk.WrapSDKContext(ctx) params := types.DefaultParams() keeper.SetParams(ctx, params) diff --git a/x/supplier/keeper/query_proof_test.go b/x/supplier/keeper/query_proof_test.go index d932b43cb..a082d6e10 100644 --- a/x/supplier/keeper/query_proof_test.go +++ b/x/supplier/keeper/query_proof_test.go @@ -6,19 +6,20 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" - keepertest "github.com/pokt-network/poktroll/testutil/keeper" - "github.com/pokt-network/poktroll/testutil/nullify" - "github.com/pokt-network/poktroll/x/supplier/types" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + + keepertest "github.com/pokt-network/poktroll/testutil/keeper" + "github.com/pokt-network/poktroll/testutil/nullify" + "github.com/pokt-network/poktroll/x/supplier/types" ) // Prevent strconv unused error var _ = strconv.IntSize func TestProofQuerySingle(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) wctx := sdk.WrapSDKContext(ctx) msgs := createNProofs(keeper, ctx, 2) tests := []struct { @@ -70,7 +71,7 @@ func TestProofQuerySingle(t *testing.T) { } func TestProofQueryPaginated(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) wctx := sdk.WrapSDKContext(ctx) msgs := createNProofs(keeper, ctx, 5) diff --git a/x/supplier/keeper/query_supplier_test.go b/x/supplier/keeper/query_supplier_test.go index ad28a377b..bfd4f8019 100644 --- a/x/supplier/keeper/query_supplier_test.go +++ b/x/supplier/keeper/query_supplier_test.go @@ -19,7 +19,7 @@ import ( var _ = strconv.IntSize func TestSupplierQuerySingle(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) wctx := sdk.WrapSDKContext(ctx) msgs := createNSupplier(keeper, ctx, 2) tests := []struct { @@ -71,7 +71,7 @@ func TestSupplierQuerySingle(t *testing.T) { } func TestSupplierQueryPaginated(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) wctx := sdk.WrapSDKContext(ctx) msgs := createNSupplier(keeper, ctx, 5) diff --git a/x/supplier/keeper/supplier_test.go b/x/supplier/keeper/supplier_test.go index e7b901489..03b1e470a 100644 --- a/x/supplier/keeper/supplier_test.go +++ b/x/supplier/keeper/supplier_test.go @@ -50,7 +50,7 @@ func createNSupplier(keeper *keeper.Keeper, ctx sdk.Context, n int) []sharedtype } func TestSupplierGet(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) suppliers := createNSupplier(keeper, ctx, 10) for _, supplier := range suppliers { supplierFound, isSupplierFound := keeper.GetSupplier(ctx, @@ -64,7 +64,7 @@ func TestSupplierGet(t *testing.T) { } } func TestSupplierRemove(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) suppliers := createNSupplier(keeper, ctx, 10) for _, supplier := range suppliers { keeper.RemoveSupplier(ctx, @@ -78,7 +78,7 @@ func TestSupplierRemove(t *testing.T) { } func TestSupplierGetAll(t *testing.T) { - keeper, ctx := keepertest.SupplierKeeper(t) + keeper, ctx := keepertest.SupplierKeeper(t, nil) suppliers := createNSupplier(keeper, ctx, 10) require.ElementsMatch(t, nullify.Fill(suppliers), From 51801401a0e05d67da689a6a43ba52b76bbdb696 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 29 Nov 2023 10:29:20 +0100 Subject: [PATCH 06/33] chore: add claim session validation --- x/supplier/keeper/msg_server_create_claim.go | 76 ++++++++++++-------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/x/supplier/keeper/msg_server_create_claim.go b/x/supplier/keeper/msg_server_create_claim.go index 7a7722294..6112719e9 100644 --- a/x/supplier/keeper/msg_server_create_claim.go +++ b/x/supplier/keeper/msg_server_create_claim.go @@ -5,10 +5,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/pokt-network/poktroll/x/supplier/types" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" + suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" ) -func (k msgServer) CreateClaim(goCtx context.Context, msg *types.MsgCreateClaim) (*types.MsgCreateClaimResponse, error) { +func (k msgServer) CreateClaim(goCtx context.Context, msg *suppliertypes.MsgCreateClaim) (*suppliertypes.MsgCreateClaimResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) logger := k.Logger(ctx).With("method", "CreateClaim") @@ -16,44 +17,61 @@ func (k msgServer) CreateClaim(goCtx context.Context, msg *types.MsgCreateClaim) return nil, err } - claim := types.Claim{ - SupplierAddress: msg.SupplierAddress, - SessionId: msg.SessionHeader.SessionId, - SessionEndBlockHeight: uint64(msg.SessionHeader.SessionEndBlockHeight), - RootHash: msg.RootHash, + sessionRes, err := k.Keeper.sessionKeeper.GetSession(goCtx, &sessiontypes.QueryGetSessionRequest{ + ApplicationAddress: msg.SessionHeader.ApplicationAddress, + Service: msg.SessionHeader.Service, + BlockHeight: msg.SessionHeader.SessionStartBlockHeight, + }) + if err != nil { + return nil, err } - k.Keeper.InsertClaim(ctx, claim) - logger.Info("created claim for supplier %s at session ending height %d", claim.SupplierAddress, claim.SessionEndBlockHeight) - logger.Info("TODO_INCOMPLETE: Handling actual claim business logic %s", claim.SessionId) + if sessionRes.Session.SessionId != msg.SessionHeader.SessionId { + return nil, suppliertypes.ErrSupplierInvalidSessionId.Wrapf( + "claimed sessionRes ID does not match on-chain sessionRes ID; expected %q, got %q", + sessionRes.Session.SessionId, + msg.SessionHeader.SessionId, + ) + } - /* - TODO_INCOMPLETE: Handling the message + var found bool + for _, supplier := range sessionRes.GetSession().GetSuppliers() { + if supplier.Address == msg.SupplierAddress { + found = true + break + } + } - ## Validation + if !found { + return nil, suppliertypes.ErrSupplierNotFound.Wrapf( + "supplier address %q in session ID %q", + msg.SupplierAddress, + sessionRes.GetSession().GetSessionId(), + ) + } - ### Session validation - 1. [ ] claimed session ID matches on-chain session ID - 2. [ ] this supplier is in the session's suppliers list + /* + TODO_INCOMPLETE: - ### Msg distribution validation (depends on session validation) + ### Msg distribution validation (depends on sessionRes validation) 1. [ ] governance-based earliest block offset 2. [ ] pseudo-randomize earliest block offset ### Claim validation - 1. [ ] session validation + 1. [x] sessionRes validation 2. [ ] msg distribution validation - - ## Persistence - 1. [ ] create claim message - - supplier address - - session header - - claim - 2. [ ] last block height commitment; derives: - - last block committed hash, must match proof path - - session ID (?) */ - _ = ctx - return &types.MsgCreateClaimResponse{}, nil + // Construct and insert claim after all validation. + claim := suppliertypes.Claim{ + SupplierAddress: msg.SupplierAddress, + SessionId: msg.SessionHeader.SessionId, + SessionEndBlockHeight: uint64(msg.SessionHeader.SessionEndBlockHeight), + RootHash: msg.RootHash, + } + k.Keeper.InsertClaim(ctx, claim) + + logger.Info("created claim for supplier %s at sessionRes ending height %d", claim.SupplierAddress, claim.SessionEndBlockHeight) + + return &suppliertypes.MsgCreateClaimResponse{}, nil } From 4dfe48a73db2a6601849a59fc31a4190f548add9 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 29 Nov 2023 10:30:10 +0100 Subject: [PATCH 07/33] test: claim message validation unit coverage --- .../keeper/msg_server_create_claim_test.go | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 x/supplier/keeper/msg_server_create_claim_test.go diff --git a/x/supplier/keeper/msg_server_create_claim_test.go b/x/supplier/keeper/msg_server_create_claim_test.go new file mode 100644 index 000000000..7c0d81ebc --- /dev/null +++ b/x/supplier/keeper/msg_server_create_claim_test.go @@ -0,0 +1,125 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + keepertest "github.com/pokt-network/poktroll/testutil/keeper" + "github.com/pokt-network/poktroll/testutil/sample" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" + "github.com/pokt-network/poktroll/x/supplier/keeper" + "github.com/pokt-network/poktroll/x/supplier/types" + suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" +) + +func TestMsgServer_CreateClaim_Success(t *testing.T) { + appAddr, supplierAddr := sample.AccAddress(), sample.AccAddress() + + // TODO_IN_THIS_COMMIT: dedup & refactor to a test helper. + sessionMockMap := keepertest.SessionMetaFixturesByAppAddr{ + appAddr: keepertest.SessionMetaFixture{ + SessionId: "mock_session_id", + AppAddr: appAddr, + SupplierAddr: supplierAddr, + }, + } + + supplierKeeper, sdkCtx := keepertest.SupplierKeeper(t, sessionMockMap) + srv := keeper.NewMsgServerImpl(*supplierKeeper) + ctx := sdk.WrapSDKContext(sdkCtx) + + claimMsg := newTestClaimMsg(t) + claimMsg.SupplierAddress = supplierAddr + claimMsg.SessionHeader.ApplicationAddress = appAddr + + createClaimRes, err := srv.CreateClaim(ctx, claimMsg) + require.NoError(t, err) + require.NotNil(t, createClaimRes) + + claimRes, err := supplierKeeper.AllClaims(sdkCtx, &types.QueryAllClaimsRequest{}) + require.NoError(t, err) + + claims := claimRes.GetClaim() + require.Lenf(t, claims, 1, "expected 1 claim, got %d", len(claims)) + require.Equal(t, claimMsg.SessionHeader.SessionId, claims[0].SessionId) + require.Equal(t, claimMsg.SupplierAddress, claims[0].SupplierAddress) + require.Equal(t, uint64(claimMsg.SessionHeader.GetSessionEndBlockHeight()), claims[0].SessionEndBlockHeight) + require.Equal(t, claimMsg.RootHash, claims[0].RootHash) +} + +func TestMsgServer_CreateClaim_Error(t *testing.T) { + appAddr, supplierAddr := sample.AccAddress(), sample.AccAddress() + + // TODO_IN_THIS_COMMIT: dedup & refactor to a test helper. + sessionMockMap := keepertest.SessionMetaFixturesByAppAddr{ + appAddr: keepertest.SessionMetaFixture{ + SessionId: "mock_session_id", + AppAddr: appAddr, + SupplierAddr: supplierAddr, + }, + } + supplierKeeper, sdkCtx := keepertest.SupplierKeeper(t, sessionMockMap) + srv := keeper.NewMsgServerImpl(*supplierKeeper) + ctx := sdk.WrapSDKContext(sdkCtx) + + tests := []struct { + desc string + claimMsgFn func(t *testing.T) *types.MsgCreateClaim + expectedErr error + }{ + { + desc: "on-chain session ID must match claim msg session ID", + claimMsgFn: func(t *testing.T) *types.MsgCreateClaim { + msg := newTestClaimMsg(t) + msg.SupplierAddress = supplierAddr + msg.SessionHeader.ApplicationAddress = appAddr + msg.SessionHeader.SessionId = "invalid_session_id" + + return msg + }, + expectedErr: types.ErrSupplierInvalidSessionId, + }, + { + desc: "claim msg supplier address must be in the session", + claimMsgFn: func(t *testing.T) *types.MsgCreateClaim { + msg := newTestClaimMsg(t) + msg.SessionHeader.ApplicationAddress = appAddr + + // Overwrite supplier address to one not included in the session fixtures. + msg.SupplierAddress = sample.AccAddress() + + return msg + }, + expectedErr: types.ErrSupplierNotFound, + }, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + createClaimRes, err := srv.CreateClaim(ctx, tt.claimMsgFn(t)) + require.ErrorIs(t, err, tt.expectedErr) + require.Nil(t, createClaimRes) + }) + } +} + +func newTestClaimMsg(t *testing.T) *suppliertypes.MsgCreateClaim { + t.Helper() + + return suppliertypes.NewMsgCreateClaim( + sample.AccAddress(), + &sessiontypes.SessionHeader{ + ApplicationAddress: sample.AccAddress(), + SessionStartBlockHeight: 1, + SessionId: "mock_session_id", + Service: &sharedtypes.Service{ + Id: "svc1", + Name: "svc1", + }, + }, + []byte{0, 0, 0, 0}, + ) +} From 5721b519ea24081ad79cc3c5897a2422ad225cc4 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 29 Nov 2023 10:31:13 +0100 Subject: [PATCH 08/33] test: e2e session lifecycle --- e2e/tests/session.feature | 9 ++ e2e/tests/session_steps_test.go | 152 ++++++++++++++++++++++++++++++++ testutil/testclient/localnet.go | 11 ++- 3 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 e2e/tests/session.feature create mode 100644 e2e/tests/session_steps_test.go diff --git a/e2e/tests/session.feature b/e2e/tests/session.feature new file mode 100644 index 000000000..6d98e7c71 --- /dev/null +++ b/e2e/tests/session.feature @@ -0,0 +1,9 @@ +Feature: Session Namespace + + Scenario: Supplier completes claim/proof lifecycle for a valid session + Given the user has the pocketd binary installed + And the supplier "supplier1" has serviced a session of relays for application "app1" + When after the supplier creates a claim for the session + Then the claim created by supplier "supplier1" should be persisted on-chain +# TODO_IN_THIS_COMMIT: ... +# And an event should be emitted... diff --git a/e2e/tests/session_steps_test.go b/e2e/tests/session_steps_test.go new file mode 100644 index 000000000..9729a2272 --- /dev/null +++ b/e2e/tests/session_steps_test.go @@ -0,0 +1,152 @@ +//go:build e2e + +package e2e + +import ( + "context" + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/stretchr/testify/require" + + eventsquery "github.com/pokt-network/poktroll/pkg/client/events_query" + "github.com/pokt-network/poktroll/pkg/either" + "github.com/pokt-network/poktroll/pkg/observable" + "github.com/pokt-network/poktroll/pkg/observable/channel" + "github.com/pokt-network/poktroll/testutil/testclient" + suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" +) + +const ( + createClaimTimeoutDuration = 10 * time.Second + eitherEventsReplayBufferSize = 100 +) + +var ( + eitherEventsBzReplayObsKey = "eitherEventsBzReplayObsKey" + supplierAddressKey = "supplierAddressKey" +) + +func (s *suite) AfterTheSupplierCreatesAClaimForTheSession() { + var ctx, done = context.WithCancel(context.Background()) + + eitherEventsBzReplayObs := s.scenarioState[eitherEventsBzReplayObsKey].(observable.ReplayObservable[either.Bytes]) + + channel.ForEach[either.Bytes]( + ctx, eitherEventsBzReplayObs, + func(_ context.Context, eitherEventBz either.Bytes) { + eventBz, err := eitherEventBz.ValueOrError() + require.NoError(s, err) + + if strings.Contains(string(eventBz), "jsonrpc") { + return + } + + // Unmarshal byte data into a TxEvent object. + // Try to deserialize the provided bytes into a TxEvent. + err = json.Unmarshal(eventBz, &map[string]any{}) + require.NoError(s, err) + + var found bool + // TODO_IN_THIS_COMMIT: improve or comment... + for _, event := range ((map[string]any{"result": nil})["result"]).(map[string]any)["events"].([]any) { + for _, attribute := range event.(map[string]any)["attributes"].([]any) { + if attribute.(map[string]any)["key"] == "action" { + require.Equal( + s, "/pocket.supplier.MsgCreateClaim", + attribute.(map[string]any)["value"], + ) + found = true + break + } + } + if found { + break + } + } + require.Truef(s, found, "unable to find event action attribute") + + done() + }, + ) + + select { + case <-ctx.Done(): + case <-time.After(createClaimTimeoutDuration): + s.Fatal("timed out waiting for claim to be created") + } +} + +func (s *suite) TheClaimCreatedBySupplierShouldBePersistedOnchain(supplierName string) { + ctx := context.Background() + + // TODO_IN_THIS_COMMIT: set up in before hooks + flagSet := testclient.NewLocalnetFlagSet(s) + clientCtx := testclient.NewLocalnetClientCtx(s, flagSet) + supplierQueryClient := suppliertypes.NewQueryClient(clientCtx) + + claimsRes, err := supplierQueryClient.AllClaims(ctx, &suppliertypes.QueryAllClaimsRequest{ + Filter: &suppliertypes.QueryAllClaimsRequest_SupplierAddress{ + SupplierAddress: accNameToAddrMap[supplierName], + }, + }) + require.NoError(s, err) + require.NotNil(s, claimsRes) + + // TODO_IN_THIS_COMMIT: query claims before this step, perhaps note the highest + // session end height, then compare against queried claims in this step, + // asserting the length is +1 and the highest session end height increased. + //require.Lenf(s, claimsRes.Claim, 1, "expected 1 claim, got %d", len(claimsRes.Claim)) + require.NotEmpty(s, claimsRes.Claim) + + claim := claimsRes.Claim[0] + require.Equal(s, accNameToAddrMap[supplierName], claim.SupplierAddress) +} + +func (s *suite) TheSupplierHasServicedASessionOfRelaysForApplication(supplierName string, appName string) { + // TODO_IN_THIS_COMMIT: use consts or something + pocketNodeWebsocketUrl := "ws://localhost:36657/websocket" + msgClaimSenderQueryFmt := "tm.event='Tx' AND message.sender='%s'" + msgSenderQuery := fmt.Sprintf(msgClaimSenderQueryFmt, accNameToAddrMap[supplierName]) + s.Logf("msgSenderQuery: %s", msgSenderQuery) + ctx := context.Background() + + // TODO_TECHDEBT: refactor to use EventsReplayClient once available. + eventsQueryClient := eventsquery.NewEventsQueryClient(pocketNodeWebsocketUrl) + eitherEventsBzObs, err := eventsQueryClient.EventsBytes(ctx, msgSenderQuery) + require.NoError(s, err) + + eitherEventsBytesObs := observable.Observable[either.Bytes](eitherEventsBzObs) + eitherEventsBzRelayObs := channel.ToReplayObservable(ctx, eitherEventsReplayBufferSize, eitherEventsBytesObs) + s.scenarioState[eitherEventsBzReplayObsKey] = eitherEventsBzRelayObs + + // TODO_IN_THIS_COMMMIT: use consts or something + s.sendRelaysForSession( + appName, + supplierName, + "anvil", + 5, + ) +} + +// TODO_IN_THIS_COMMIT: rename +func (s *suite) sendRelaysForSession( + appName string, + supplierName string, + serviceId string, + relayLimit int, +) { + s.TheApplicationIsStakedForService(appName, serviceId) + s.TheSupplierIsStakedForService(supplierName, serviceId) + s.TheSessionForApplicationAndServiceContainsTheSupplier(appName, serviceId, supplierName) + + // TODO_IN_THIS_COMMIT: something better + data := `{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}` + + for i := 0; i < relayLimit; i++ { + s.TheApplicationSendsTheSupplierARequestForServiceWithData(appName, supplierName, serviceId, data) + s.TheApplicationReceivesASuccessfulRelayResponseSignedBy(appName, supplierName) + } +} diff --git a/testutil/testclient/localnet.go b/testutil/testclient/localnet.go index 61d5c0ad8..95380917e 100644 --- a/testutil/testclient/localnet.go +++ b/testutil/testclient/localnet.go @@ -1,11 +1,10 @@ package testclient import ( - "testing" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/regen-network/gocuke" "github.com/spf13/pflag" "github.com/stretchr/testify/require" @@ -35,7 +34,9 @@ func init() { // // Returns: // - A pointer to a populated client.Context instance suitable for localnet usage. -func NewLocalnetClientCtx(t *testing.T, flagSet *pflag.FlagSet) *client.Context { +func NewLocalnetClientCtx(t gocuke.TestingT, flagSet *pflag.FlagSet) *client.Context { + t.Helper() + homedir := app.DefaultNodeHome clientCtx := client.Context{}. WithCodec(EncodingConfig.Marshaler). @@ -57,7 +58,9 @@ func NewLocalnetClientCtx(t *testing.T, flagSet *pflag.FlagSet) *client.Context // // Returns: // - A flag set populated with flags tailored for localnet environments. -func NewLocalnetFlagSet(t *testing.T) *pflag.FlagSet { +func NewLocalnetFlagSet(t gocuke.TestingT) *pflag.FlagSet { + t.Helper() + mockFlagSet := pflag.NewFlagSet("test", pflag.ContinueOnError) mockFlagSet.String(flags.FlagNode, "tcp://127.0.0.1:36657", "use localnet poktrolld node") mockFlagSet.String(flags.FlagHome, "", "use localnet poktrolld node") From 65d92e3e06dbcc8cb1bf8b45ad3f92dd10c4ea81 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 30 Nov 2023 20:42:33 +0100 Subject: [PATCH 09/33] chore: add `ApplicationModuleGenesisStateWithAccounts` testutil --- testutil/network/network.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/testutil/network/network.go b/testutil/network/network.go index d05c283be..67999ef3a 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -126,6 +126,27 @@ func DefaultApplicationModuleGenesisState(t *testing.T, n int) *apptypes.Genesis return state } +// TODO_IN_THIS_COMMIT: fix comment... +// ApplicationModuleGenesisStateWithAccount generates a GenesisState object with a single supplier with the given address. +func ApplicationModuleGenesisStateWithAccounts(t *testing.T, addresses []string) *apptypes.GenesisState { + t.Helper() + state := apptypes.DefaultGenesis() + for _, addr := range addresses { + application := apptypes.Application{ + Address: addr, + Stake: &sdk.Coin{Denom: "upokt", Amount: sdk.NewInt(10000)}, + ServiceConfigs: []*sharedtypes.ApplicationServiceConfig{ + { + Service: &sharedtypes.Service{Id: "svc1"}, + }, + }, + } + state.ApplicationList = append(state.ApplicationList, application) + } + + return state +} + // DefaultGatewayModuleGenesisState generates a GenesisState object with a given number of gateways. // It returns the populated GenesisState object. func DefaultGatewayModuleGenesisState(t *testing.T, n int) *gatewaytypes.GenesisState { From 17fb3f1e90e79703abcf7759f0706238f27b951f Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 30 Nov 2023 20:42:53 +0100 Subject: [PATCH 10/33] wip: fix claims show/list tests --- x/supplier/client/cli/query_claim_test.go | 145 +++++++++++++++++----- 1 file changed, 112 insertions(+), 33 deletions(-) diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index c36abf15a..22abab7fd 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -1,6 +1,7 @@ package cli_test import ( + "context" "encoding/base64" "encoding/json" "fmt" @@ -12,7 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" cdctypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/testutil" + "github.com/cosmos/cosmos-sdk/crypto/keyring" clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" @@ -21,7 +22,8 @@ import ( "github.com/pokt-network/poktroll/testutil/network" "github.com/pokt-network/poktroll/testutil/nullify" - "github.com/pokt-network/poktroll/testutil/sample" + "github.com/pokt-network/poktroll/testutil/testkeyring" + apptypes "github.com/pokt-network/poktroll/x/application/types" sessiontypes "github.com/pokt-network/poktroll/x/session/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" "github.com/pokt-network/poktroll/x/supplier/client/cli" @@ -31,15 +33,20 @@ import ( // TODO_TECHDEBT: This should not be hardcoded once the num blocks per session is configurable const numBlocksPerSession = 4 -func encodeSessionHeader(t *testing.T, sessionId string, sessionEndHeight int64) string { +func encodeSessionHeader( + t *testing.T, + appAddr string, + sessionId string, + sessionStartHeight int64, +) string { t.Helper() argSessionHeader := &sessiontypes.SessionHeader{ - ApplicationAddress: sample.AccAddress(), - SessionStartBlockHeight: sessionEndHeight - numBlocksPerSession, + ApplicationAddress: appAddr, + SessionStartBlockHeight: sessionStartHeight, SessionId: sessionId, - SessionEndBlockHeight: sessionEndHeight, - Service: &sharedtypes.Service{Id: "anvil"}, // hardcoded for simplicity + SessionEndBlockHeight: sessionStartHeight + numBlocksPerSession, + Service: &sharedtypes.Service{Id: "svc1"}, } cdc := codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) sessionHeaderBz := cdc.MustMarshalJSON(argSessionHeader) @@ -51,13 +58,17 @@ func createClaim( net *network.Network, ctx client.Context, supplierAddr string, - sessionId string, sessionEndHeight int64, + appAddress string, ) *types.Claim { t.Helper() + //appAddr := sample.AccAddress() rootHash := []byte("root_hash") - sessionHeaderEncoded := encodeSessionHeader(t, sessionId, sessionEndHeight) + sessionStartHeight := sessionEndHeight - numBlocksPerSession + sessionId, err := getSessionId(t, net, appAddress, supplierAddr, sessionStartHeight) + require.NoError(t, err) + sessionHeaderEncoded := encodeSessionHeader(t, appAddress, sessionId, sessionStartHeight) rootHashEncoded := base64.StdEncoding.EncodeToString(rootHash) args := []string{ @@ -84,6 +95,35 @@ func createClaim( } } +func getSessionId( + t *testing.T, + net *network.Network, + appAddr string, + supplierAddr string, + sessionStartHeight int64, +) (string, error) { + t.Helper() + ctx := context.TODO() + + sessionQueryClient := sessiontypes.NewQueryClient(net.Validators[0].ClientCtx) + res, err := sessionQueryClient.GetSession(ctx, &sessiontypes.QueryGetSessionRequest{ + ApplicationAddress: appAddr, + Service: &sharedtypes.Service{Id: "svc1"}, // hardcoded for simplicity + BlockHeight: sessionStartHeight, + }) + if err != nil { + return "", err + } + + if res.GetSession().GetSuppliers()[0].GetAddress() != supplierAddr { + return "", fmt.Errorf("supplier address %s not found in session", supplierAddr) + } + + return res.Session.SessionId, nil +} + +// TODO_CONSIDERATION: perhaps this (and/or other similar helpers) can be refactored +// into something more generic and moved into a shared testutil package. func networkWithClaimObjects( t *testing.T, numSessions int, @@ -91,43 +131,82 @@ func networkWithClaimObjects( ) (net *network.Network, claims []types.Claim) { t.Helper() - // Prepare the network + // Initialize a network config. cfg := network.DefaultConfig() + + // Construct an in-memory keyring so that it can be populated and used prior + // to network start. + kr := keyring.NewInMemory(cfg.Codec) + // Populate the in-memmory keyring with as many pre-generated accounts as + // we expect to need for the test. + testkeyring.CreatePreGeneratedKeyringAccounts(t, kr, 20) + + // Use the pre-generated accounts iterator to populate the supplier and + // application accounts and addresses lists for use in genesis state construction. + preGeneratedAccts := testkeyring.PreGeneratedAccounts().Clone() + + // Create a supplier for each session in numSessions and an app for each + // claim in numClaimsPerSession. + supplierAccts := make([]*testkeyring.PreGeneratedAccount, numSessions) + supplierAddrs := make([]string, numSessions) + for i := range supplierAccts { + account := preGeneratedAccts.MustNext() + supplierAccts[i] = account + supplierAddrs[i] = account.Address.String() + } + appAccts := make([]*testkeyring.PreGeneratedAccount, numClaimsPerSession) + appAddrs := make([]string, numClaimsPerSession) + for i := range appAccts { + account := preGeneratedAccts.MustNext() + appAccts[i] = account + appAddrs[i] = account.Address.String() + } + + // Construct supplier and application module genesis states given the account addresses. + supplierGenesisState := network.SupplierModuleGenesisStateWithAccounts(t, supplierAddrs) + supplierGenesisBuffer, err := cfg.Codec.MarshalJSON(supplierGenesisState) + require.NoError(t, err) + appGenesisState := network.ApplicationModuleGenesisStateWithAccounts(t, appAddrs) + appGenesisBuffer, err := cfg.Codec.MarshalJSON(appGenesisState) + require.NoError(t, err) + + // Add supplier and application module genesis states to the network config. + cfg.GenesisState[types.ModuleName] = supplierGenesisBuffer + cfg.GenesisState[apptypes.ModuleName] = appGenesisBuffer + + // Construct the network with the configuration. net = network.New(t, cfg) + // Only the first validator's client context is populated. + // (see: https://pkg.go.dev/github.com/cosmos/cosmos-sdk/testutil/network#pkg-overview) ctx := net.Validators[0].ClientCtx - - // Prepare the keyring for the supplier account - kr := ctx.Keyring - accounts := testutil.CreateKeyringAccounts(t, kr, numClaimsPerSession) + // Overwrite the client context's keyring with the in-memory one that contains + // our pre-generated accounts. ctx = ctx.WithKeyring(kr) // Initialize all the accounts - for i, account := range accounts { - signatureSequenceNumber := i + 1 - network.InitAccountWithSequence(t, net, account.Address, signatureSequenceNumber) + sequenceIndex := 1 + for _, supplierAcct := range supplierAccts { + network.InitAccountWithSequence(t, net, supplierAcct.Address, sequenceIndex) + sequenceIndex++ + } + for _, appAcct := range appAccts { + network.InitAccountWithSequence(t, net, appAcct.Address, sequenceIndex) + sequenceIndex++ } // need to wait for the account to be initialized in the next block require.NoError(t, net.WaitForNextBlock()) - addresses := make([]string, len(accounts)) - for i, account := range accounts { - addresses[i] = account.Address.String() - } - - // Create one supplier - supplierGenesisState := network.SupplierModuleGenesisStateWithAccounts(t, addresses) - buf, err := cfg.Codec.MarshalJSON(supplierGenesisState) - require.NoError(t, err) - cfg.GenesisState[types.ModuleName] = buf - // Create numSessions * numClaimsPerSession claims for the supplier sessionEndHeight := int64(1) - for sessionNum := 0; sessionNum < numSessions; sessionNum++ { + for _, supplierAcct := range supplierAccts { sessionEndHeight += numBlocksPerSession - sessionId := fmt.Sprintf("session_id%d", sessionNum) - for claimNum := 0; claimNum < numClaimsPerSession; claimNum++ { - supplierAddr := addresses[claimNum] - claim := createClaim(t, net, ctx, supplierAddr, sessionId, sessionEndHeight) + for _, appAcct := range appAccts { + claim := createClaim( + t, net, ctx, + supplierAcct.Address.String(), + sessionEndHeight, + appAcct.Address.String(), + ) claims = append(claims, *claim) // TODO_TECHDEBT(#196): Move this outside of the forloop so that the test iteration is faster require.NoError(t, net.WaitForNextBlock()) From 91815d11b3eb691a0fb191f4680c4cbb34e43ac6 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 1 Dec 2023 09:27:20 +0100 Subject: [PATCH 11/33] fix: bug in session supplier hydration --- x/session/keeper/session_hydrator.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x/session/keeper/session_hydrator.go b/x/session/keeper/session_hydrator.go index 38f9d529e..d91de3a49 100644 --- a/x/session/keeper/session_hydrator.go +++ b/x/session/keeper/session_hydrator.go @@ -157,7 +157,11 @@ func (k Keeper) hydrateSessionSuppliers(ctx sdk.Context, sh *sessionHydrator) er suppliers := k.supplierKeeper.GetAllSupplier(ctx) candidateSuppliers := make([]*sharedtypes.Supplier, 0) - for _, supplier := range suppliers { + for _, s := range suppliers { + // NB: Allocate a new heap variable as s is a value and we're appending + // to a slice of pointers; otherwise, we'd be appending new pointers to + // the same memory address containing the last supplier in the loop. + supplier := s // TODO_OPTIMIZE: If `supplier.Services` was a map[string]struct{}, we could eliminate `slices.Contains()`'s loop for _, supplierServiceConfig := range supplier.Services { if supplierServiceConfig.Service.Id == sh.sessionHeader.Service.Id { From d28c74c4232fabb18dd69744bb1ee61141fe040e Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 1 Dec 2023 09:28:26 +0100 Subject: [PATCH 12/33] wip: fixing tests --- testutil/network/network.go | 4 ++-- x/supplier/client/cli/query_claim_test.go | 17 +++++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/testutil/network/network.go b/testutil/network/network.go index 67999ef3a..724895947 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -128,7 +128,7 @@ func DefaultApplicationModuleGenesisState(t *testing.T, n int) *apptypes.Genesis // TODO_IN_THIS_COMMIT: fix comment... // ApplicationModuleGenesisStateWithAccount generates a GenesisState object with a single supplier with the given address. -func ApplicationModuleGenesisStateWithAccounts(t *testing.T, addresses []string) *apptypes.GenesisState { +func ApplicationModuleGenesisStateWithAddresses(t *testing.T, addresses []string) *apptypes.GenesisState { t.Helper() state := apptypes.DefaultGenesis() for _, addr := range addresses { @@ -195,7 +195,7 @@ func DefaultSupplierModuleGenesisState(t *testing.T, n int) *suppliertypes.Genes } // SupplierModuleGenesisStateWithAccount generates a GenesisState object with a single supplier with the given address. -func SupplierModuleGenesisStateWithAccounts(t *testing.T, addresses []string) *suppliertypes.GenesisState { +func SupplierModuleGenesisStateWithAddresses(t *testing.T, addresses []string) *suppliertypes.GenesisState { t.Helper() state := suppliertypes.DefaultGenesis() for _, addr := range addresses { diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index 22abab7fd..c8e38819f 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -115,9 +115,14 @@ func getSessionId( return "", err } - if res.GetSession().GetSuppliers()[0].GetAddress() != supplierAddr { - return "", fmt.Errorf("supplier address %s not found in session", supplierAddr) + var found bool + for _, supplier := range res.GetSession().GetSuppliers() { + if supplier.GetAddress() == supplierAddr { + found = true + break + } } + require.Truef(t, found, "supplier address %s not found in session", supplierAddr) return res.Session.SessionId, nil } @@ -163,10 +168,10 @@ func networkWithClaimObjects( } // Construct supplier and application module genesis states given the account addresses. - supplierGenesisState := network.SupplierModuleGenesisStateWithAccounts(t, supplierAddrs) + supplierGenesisState := network.SupplierModuleGenesisStateWithAddresses(t, supplierAddrs) supplierGenesisBuffer, err := cfg.Codec.MarshalJSON(supplierGenesisState) require.NoError(t, err) - appGenesisState := network.ApplicationModuleGenesisStateWithAccounts(t, appAddrs) + appGenesisState := network.ApplicationModuleGenesisStateWithAddresses(t, appAddrs) appGenesisBuffer, err := cfg.Codec.MarshalJSON(appGenesisState) require.NoError(t, err) @@ -366,11 +371,11 @@ func TestClaim_List(t *testing.T) { var resp types.QueryAllClaimsResponse require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) - require.Equal(t, numSessions, int(resp.Pagination.Total)) require.ElementsMatch(t, nullify.Fill(expectedClaims), nullify.Fill(resp.Claim), ) + require.Equal(t, numClaimsPerSession, int(resp.Pagination.Total)) }) t.Run("BySession", func(t *testing.T) { @@ -391,11 +396,11 @@ func TestClaim_List(t *testing.T) { var resp types.QueryAllClaimsResponse require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) - require.Equal(t, numClaimsPerSession, int(resp.Pagination.Total)) require.ElementsMatch(t, nullify.Fill(expectedClaims), nullify.Fill(resp.Claim), ) + require.Equal(t, 1, int(resp.Pagination.Total)) }) t.Run("ByHeight", func(t *testing.T) { From 304d51fb68dff03cc75f9cf117acb9324463c875 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 1 Dec 2023 11:37:34 +0100 Subject: [PATCH 13/33] wip: fixing tests --- x/supplier/client/cli/query_claim_test.go | 83 +++++++++++++++-------- 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index c8e38819f..9dbd367da 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -131,8 +131,11 @@ func getSessionId( // into something more generic and moved into a shared testutil package. func networkWithClaimObjects( t *testing.T, - numSessions int, - numClaimsPerSession int, + sessionCount int, + supplierCount int, + appCount int, + // TODO_THIS_COMMIT: hook up to genesis state generation... + serviceCount int, ) (net *network.Network, claims []types.Claim) { t.Helper() @@ -150,17 +153,17 @@ func networkWithClaimObjects( // application accounts and addresses lists for use in genesis state construction. preGeneratedAccts := testkeyring.PreGeneratedAccounts().Clone() - // Create a supplier for each session in numSessions and an app for each + // Create a supplier for each session in numClaimsSessions and an app for each // claim in numClaimsPerSession. - supplierAccts := make([]*testkeyring.PreGeneratedAccount, numSessions) - supplierAddrs := make([]string, numSessions) + supplierAccts := make([]*testkeyring.PreGeneratedAccount, supplierCount) + supplierAddrs := make([]string, supplierCount) for i := range supplierAccts { account := preGeneratedAccts.MustNext() supplierAccts[i] = account supplierAddrs[i] = account.Address.String() } - appAccts := make([]*testkeyring.PreGeneratedAccount, numClaimsPerSession) - appAddrs := make([]string, numClaimsPerSession) + appAccts := make([]*testkeyring.PreGeneratedAccount, appCount) + appAddrs := make([]string, appCount) for i := range appAccts { account := preGeneratedAccts.MustNext() appAccts[i] = account @@ -201,20 +204,23 @@ func networkWithClaimObjects( // need to wait for the account to be initialized in the next block require.NoError(t, net.WaitForNextBlock()) - // Create numSessions * numClaimsPerSession claims for the supplier + // Create sessionCount * numClaimsPerSession claims for the supplier sessionEndHeight := int64(1) - for _, supplierAcct := range supplierAccts { + for sessionIdx := 0; sessionIdx < sessionCount; sessionIdx++ { sessionEndHeight += numBlocksPerSession - for _, appAcct := range appAccts { - claim := createClaim( - t, net, ctx, - supplierAcct.Address.String(), - sessionEndHeight, - appAcct.Address.String(), - ) - claims = append(claims, *claim) - // TODO_TECHDEBT(#196): Move this outside of the forloop so that the test iteration is faster - require.NoError(t, net.WaitForNextBlock()) + // TODO_IN_THIS_COMMIT: numClaimsPerSession == supplierCount * appCount + for _, supplierAcct := range supplierAccts { + for _, appAcct := range appAccts { + claim := createClaim( + t, net, ctx, + supplierAcct.Address.String(), + sessionEndHeight, + appAcct.Address.String(), + ) + claims = append(claims, *claim) + // TODO_TECHDEBT(#196): Move this outside of the forloop so that the test iteration is faster + require.NoError(t, net.WaitForNextBlock()) + } } } @@ -222,10 +228,18 @@ func networkWithClaimObjects( } func TestClaim_Show(t *testing.T) { - numSessions := 1 - numClaimsPerSession := 2 - - net, claims := networkWithClaimObjects(t, numSessions, numClaimsPerSession) + sessionCount := 1 + supplierCount := 3 + appCount := 3 + serviceCount := 1 + //numClaimsPerSession := supplierCount * appCount * serviceCount + + net, claims := networkWithClaimObjects( + t, sessionCount, + appCount, + supplierCount, + serviceCount, + ) ctx := net.Validators[0].ClientCtx common := []string{ @@ -292,11 +306,20 @@ func TestClaim_Show(t *testing.T) { } func TestClaim_List(t *testing.T) { - numSessions := 2 - numClaimsPerSession := 5 - totalClaims := numSessions * numClaimsPerSession - - net, claims := networkWithClaimObjects(t, numSessions, numClaimsPerSession) + sessionCount := 2 + supplierCount := 4 + appCount := 3 + serviceCount := 1 + // Each supplier will submit a claim for each app x service combination (per session). + numClaimsPerSession := supplierCount * appCount * serviceCount + totalClaims := sessionCount * numClaimsPerSession + + net, claims := networkWithClaimObjects( + t, sessionCount, + supplierCount, + appCount, + serviceCount, + ) ctx := net.Validators[0].ClientCtx prepareArgs := func(next []byte, offset, limit uint64, total bool) []string { @@ -375,7 +398,7 @@ func TestClaim_List(t *testing.T) { nullify.Fill(expectedClaims), nullify.Fill(resp.Claim), ) - require.Equal(t, numClaimsPerSession, int(resp.Pagination.Total)) + require.Equal(t, sessionCount*appCount, int(resp.Pagination.Total)) }) t.Run("BySession", func(t *testing.T) { @@ -400,7 +423,7 @@ func TestClaim_List(t *testing.T) { nullify.Fill(expectedClaims), nullify.Fill(resp.Claim), ) - require.Equal(t, 1, int(resp.Pagination.Total)) + require.Equal(t, supplierCount, int(resp.Pagination.Total)) }) t.Run("ByHeight", func(t *testing.T) { From d02d5d7a2053318e0a159714c73d4027f883a905 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 1 Dec 2023 11:54:06 +0100 Subject: [PATCH 14/33] chore: update mock node flag with in-tilt host --- testutil/testclient/localnet.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/testutil/testclient/localnet.go b/testutil/testclient/localnet.go index 95380917e..eea7624c9 100644 --- a/testutil/testclient/localnet.go +++ b/testutil/testclient/localnet.go @@ -62,7 +62,9 @@ func NewLocalnetFlagSet(t gocuke.TestingT) *pflag.FlagSet { t.Helper() mockFlagSet := pflag.NewFlagSet("test", pflag.ContinueOnError) - mockFlagSet.String(flags.FlagNode, "tcp://127.0.0.1:36657", "use localnet poktrolld node") + // TODO_IMPROVE: It would be nice if the value could be set correctly based + // on whether the test using it is running in tilt or not. + mockFlagSet.String(flags.FlagNode, "tcp://poktroll-sequencer:36657", "use localnet poktrolld node") mockFlagSet.String(flags.FlagHome, "", "use localnet poktrolld node") mockFlagSet.String(flags.FlagKeyringBackend, "test", "use test keyring") err := mockFlagSet.Parse([]string{}) From d191d395cfe17bf828efbc417ca57ade097e6cb4 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 1 Dec 2023 12:38:25 +0100 Subject: [PATCH 15/33] wip: debugging --- e2e/tests/session_steps_test.go | 2 +- testutil/testclient/localnet.go | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/e2e/tests/session_steps_test.go b/e2e/tests/session_steps_test.go index 9729a2272..2eb2f702c 100644 --- a/e2e/tests/session_steps_test.go +++ b/e2e/tests/session_steps_test.go @@ -107,7 +107,7 @@ func (s *suite) TheClaimCreatedBySupplierShouldBePersistedOnchain(supplierName s func (s *suite) TheSupplierHasServicedASessionOfRelaysForApplication(supplierName string, appName string) { // TODO_IN_THIS_COMMIT: use consts or something - pocketNodeWebsocketUrl := "ws://localhost:36657/websocket" + pocketNodeWebsocketUrl := "ws://pocket-sequencer:36657/websocket" msgClaimSenderQueryFmt := "tm.event='Tx' AND message.sender='%s'" msgSenderQuery := fmt.Sprintf(msgClaimSenderQueryFmt, accNameToAddrMap[supplierName]) s.Logf("msgSenderQuery: %s", msgSenderQuery) diff --git a/testutil/testclient/localnet.go b/testutil/testclient/localnet.go index eea7624c9..a11578ae1 100644 --- a/testutil/testclient/localnet.go +++ b/testutil/testclient/localnet.go @@ -13,7 +13,10 @@ import ( ) // CometLocalWebsocketURL provides a default URL pointing to the localnet websocket endpoint. -const CometLocalWebsocketURL = "ws://localhost:36657/websocket" +// +// TODO_IMPROVE: It would be nice if the value could be set correctly based +// on whether the test using it is running in tilt or not. +const CometLocalWebsocketURL = "ws://poktroll-sequencer:36657/websocket" // EncodingConfig encapsulates encoding configurations for the Pocket application. var EncodingConfig = app.MakeEncodingConfig() From 51cabc398535dcdbe4a0c810f509a052e04e66e1 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 1 Dec 2023 13:16:15 +0100 Subject: [PATCH 16/33] wip: debugging --- e2e/tests/session_steps_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/e2e/tests/session_steps_test.go b/e2e/tests/session_steps_test.go index 2eb2f702c..88d346c53 100644 --- a/e2e/tests/session_steps_test.go +++ b/e2e/tests/session_steps_test.go @@ -107,7 +107,8 @@ func (s *suite) TheClaimCreatedBySupplierShouldBePersistedOnchain(supplierName s func (s *suite) TheSupplierHasServicedASessionOfRelaysForApplication(supplierName string, appName string) { // TODO_IN_THIS_COMMIT: use consts or something - pocketNodeWebsocketUrl := "ws://pocket-sequencer:36657/websocket" + // TODO_IN_THIS_COMMIT: use testclient.CometLocalWebsocketURL instead. + pocketNodeWebsocketUrl := "ws://poktroll-sequencer:36657/websocket" msgClaimSenderQueryFmt := "tm.event='Tx' AND message.sender='%s'" msgSenderQuery := fmt.Sprintf(msgClaimSenderQueryFmt, accNameToAddrMap[supplierName]) s.Logf("msgSenderQuery: %s", msgSenderQuery) From c3926b104b63642e35eeec1671966f1f7f40415a Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 1 Dec 2023 20:50:16 +0100 Subject: [PATCH 17/33] chore: self-review improvements --- Makefile | 4 ++++ testutil/testkeyring/accounts.go | 1 - testutil/testkeyring/gen_accounts/gen.go | 2 ++ testutil/testkeyring/gen_accounts/template.go | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5252fd2bb..a3660cd25 100644 --- a/Makefile +++ b/Makefile @@ -177,6 +177,10 @@ go_mockgen: ## Use `mockgen` to generate mocks used for testing purposes of all go_fixturegen: ## Generate fixture data for unit tests go generate ./pkg/relayer/miner/miner_test.go +.PHONY: go_test_accountgen +go_test_accountgen: ## Generate test accounts for usage in test environments + go generate ./testutil/testkeyring/keyring.go + .PHONY: go_develop go_develop: proto_regen go_mockgen ## Generate protos and mocks diff --git a/testutil/testkeyring/accounts.go b/testutil/testkeyring/accounts.go index ad96b8bda..6be540540 100644 --- a/testutil/testkeyring/accounts.go +++ b/testutil/testkeyring/accounts.go @@ -29,7 +29,6 @@ type PreGeneratedAccountIterator struct { // an error if the index is out of range. func PreGeneratedAccountAtIndex(index uint32) (*PreGeneratedAccount, error) { if preGeneratedAccounts.nextIndex >= uint32(len(preGeneratedAccounts.accounts)) { - // TODO_IN_THIS_COMMIT: refactor error... return nil, ErrPreGeneratedAccountIndexOutOfRange.Wrapf("%d", index) } diff --git a/testutil/testkeyring/gen_accounts/gen.go b/testutil/testkeyring/gen_accounts/gen.go index 7e0e72590..ca7c1549f 100644 --- a/testutil/testkeyring/gen_accounts/gen.go +++ b/testutil/testkeyring/gen_accounts/gen.go @@ -16,6 +16,8 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/types" + "github.com/pokt-network/poktroll/testutil/testkeyring" + "github.com/pokt-network/poktroll/app" ) diff --git a/testutil/testkeyring/gen_accounts/template.go b/testutil/testkeyring/gen_accounts/template.go index b546c0fef..522907034 100644 --- a/testutil/testkeyring/gen_accounts/template.go +++ b/testutil/testkeyring/gen_accounts/template.go @@ -13,7 +13,7 @@ var ( // // To regenerate this file, use make go_test_accountgen or go generate ./testutil/network/keyring.go. -package testaccounts +package testkeyring var ( preGeneratedAccounts = NewPreGeneratedAccountIterator( From 7814b008f6e5d80f37aabd5d4a68bdfbf4e110cd Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 4 Dec 2023 11:19:53 +0100 Subject: [PATCH 18/33] chore: review feedback improvements --- e2e/tests/init_test.go | 13 +- e2e/tests/session.feature | 6 +- e2e/tests/session_steps_test.go | 89 ++++---- pkg/client/tx/client.go | 6 +- testutil/keeper/supplier.go | 30 +-- testutil/network/network.go | 7 +- testutil/supplier/fixtures.go | 112 +++++++++ testutil/testkeyring/accounts.go | 1 - x/supplier/client/cli/helpers_test.go | 214 ++++++++++++++++++ x/supplier/client/cli/query_claim_test.go | 212 ----------------- x/supplier/keeper/msg_server_create_claim.go | 50 +++- .../keeper/msg_server_create_claim_test.go | 28 +-- 12 files changed, 454 insertions(+), 314 deletions(-) create mode 100644 testutil/supplier/fixtures.go diff --git a/e2e/tests/init_test.go b/e2e/tests/init_test.go index 8935e1240..5fa6fa3f2 100644 --- a/e2e/tests/init_test.go +++ b/e2e/tests/init_test.go @@ -19,6 +19,7 @@ import ( "github.com/stretchr/testify/require" "github.com/pokt-network/poktroll/app" + "github.com/pokt-network/poktroll/testutil/testclient" apptypes "github.com/pokt-network/poktroll/x/application/types" sessiontypes "github.com/pokt-network/poktroll/x/session/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" @@ -59,9 +60,10 @@ func TestMain(m *testing.M) { type suite struct { gocuke.TestingT - pocketd *pocketdBin - scenarioState map[string]any // temporary state for each scenario - cdc codec.Codec + pocketd *pocketdBin + scenarioState map[string]any // temporary state for each scenario + cdc codec.Codec + supplierQueryClient suppliertypes.QueryClient } func (s *suite) Before() { @@ -71,6 +73,11 @@ func (s *suite) Before() { s.buildAddrMap() s.buildAppMap() s.buildSupplierMap() + + // TODO_IN_THIS_COMMIT: set up in before hooks + flagSet := testclient.NewLocalnetFlagSet(s) + clientCtx := testclient.NewLocalnetClientCtx(s, flagSet) + s.supplierQueryClient = suppliertypes.NewQueryClient(clientCtx) } // TestFeatures runs the e2e tests specified in any .features files in this directory diff --git a/e2e/tests/session.feature b/e2e/tests/session.feature index 6d98e7c71..cc03a5029 100644 --- a/e2e/tests/session.feature +++ b/e2e/tests/session.feature @@ -2,8 +2,8 @@ Feature: Session Namespace Scenario: Supplier completes claim/proof lifecycle for a valid session Given the user has the pocketd binary installed - And the supplier "supplier1" has serviced a session of relays for application "app1" - When after the supplier creates a claim for the session - Then the claim created by supplier "supplier1" should be persisted on-chain + When the supplier "supplier1" has serviced a session with "5" relays for service "svc1" for application "app1" + And after the supplier creates a claim for the session for service "svc1" for application "app1" + Then the claim created by supplier "supplier1" for service "svc1" for application "app1" should be persisted on-chain # TODO_IN_THIS_COMMIT: ... # And an event should be emitted... diff --git a/e2e/tests/session_steps_test.go b/e2e/tests/session_steps_test.go index 88d346c53..c097960c2 100644 --- a/e2e/tests/session_steps_test.go +++ b/e2e/tests/session_steps_test.go @@ -6,12 +6,14 @@ import ( "context" "encoding/json" "fmt" + "strconv" "strings" "time" "github.com/stretchr/testify/require" eventsquery "github.com/pokt-network/poktroll/pkg/client/events_query" + "github.com/pokt-network/poktroll/pkg/client/tx" "github.com/pokt-network/poktroll/pkg/either" "github.com/pokt-network/poktroll/pkg/observable" "github.com/pokt-network/poktroll/pkg/observable/channel" @@ -22,18 +24,21 @@ import ( const ( createClaimTimeoutDuration = 10 * time.Second eitherEventsReplayBufferSize = 100 + msgClaimSenderQueryFmt = "tm.event='Tx' AND message.sender='%s'" + testServiceId = "anvil" + eitherEventsBzReplayObsKey = "eitherEventsBzReplayObsKey" + preExistingClaimsKey = "preExistingClaimsKey" ) -var ( - eitherEventsBzReplayObsKey = "eitherEventsBzReplayObsKey" - supplierAddressKey = "supplierAddressKey" -) - -func (s *suite) AfterTheSupplierCreatesAClaimForTheSession() { +func (s *suite) AfterTheSupplierCreatesAClaimForTheSessionForServiceForApplication(serviceId, appName string) { var ctx, done = context.WithCancel(context.Background()) + // TODO_CONSIDERATION: if this test suite gets more complex, it might make + // sense to refactor this key into a function that takes serviceId and appName + // as arguments and returns the key. eitherEventsBzReplayObs := s.scenarioState[eitherEventsBzReplayObsKey].(observable.ReplayObservable[either.Bytes]) + // TODO(#220): refactor to use EventsReplayClient once available. channel.ForEach[either.Bytes]( ctx, eitherEventsBzReplayObs, func(_ context.Context, eitherEventBz either.Bytes) { @@ -44,19 +49,18 @@ func (s *suite) AfterTheSupplierCreatesAClaimForTheSession() { return } - // Unmarshal byte data into a TxEvent object. - // Try to deserialize the provided bytes into a TxEvent. - err = json.Unmarshal(eventBz, &map[string]any{}) + // Unmarshal event data into a TxEventResponse object. + txEvent := &tx.TxEvent{} + err = json.Unmarshal(eventBz, txEvent) require.NoError(s, err) var found bool - // TODO_IN_THIS_COMMIT: improve or comment... - for _, event := range ((map[string]any{"result": nil})["result"]).(map[string]any)["events"].([]any) { - for _, attribute := range event.(map[string]any)["attributes"].([]any) { - if attribute.(map[string]any)["key"] == "action" { + for _, event := range txEvent.Result.Events { + for _, attribute := range event.Attributes { + if attribute.Key == "action" { require.Equal( s, "/pocket.supplier.MsgCreateClaim", - attribute.(map[string]any)["value"], + attribute.Value, ) found = true break @@ -79,15 +83,10 @@ func (s *suite) AfterTheSupplierCreatesAClaimForTheSession() { } } -func (s *suite) TheClaimCreatedBySupplierShouldBePersistedOnchain(supplierName string) { +func (s *suite) TheClaimCreatedBySupplierForServiceForApplicationShouldBePersistedOnchain(supplierName, serviceId, appName string) { ctx := context.Background() - // TODO_IN_THIS_COMMIT: set up in before hooks - flagSet := testclient.NewLocalnetFlagSet(s) - clientCtx := testclient.NewLocalnetClientCtx(s, flagSet) - supplierQueryClient := suppliertypes.NewQueryClient(clientCtx) - - claimsRes, err := supplierQueryClient.AllClaims(ctx, &suppliertypes.QueryAllClaimsRequest{ + claimsRes, err := s.supplierQueryClient.AllClaims(ctx, &suppliertypes.QueryAllClaimsRequest{ Filter: &suppliertypes.QueryAllClaimsRequest_SupplierAddress{ SupplierAddress: accNameToAddrMap[supplierName], }, @@ -95,27 +94,39 @@ func (s *suite) TheClaimCreatedBySupplierShouldBePersistedOnchain(supplierName s require.NoError(s, err) require.NotNil(s, claimsRes) - // TODO_IN_THIS_COMMIT: query claims before this step, perhaps note the highest - // session end height, then compare against queried claims in this step, - // asserting the length is +1 and the highest session end height increased. - //require.Lenf(s, claimsRes.Claim, 1, "expected 1 claim, got %d", len(claimsRes.Claim)) - require.NotEmpty(s, claimsRes.Claim) + // Assert that the number of claims has increased by one. + preExistingClaims := s.scenarioState[preExistingClaimsKey].([]suppliertypes.Claim) + require.Len(s, claimsRes.Claim, len(preExistingClaims)+1) + + // TODO_IMPROVE: assert that the root hash of the claim contains the correct + // SMST sum. The sum can be retrieved by parsing the last 8 bytes as a + // binary-encoded uint64; e.g. something like: + // `binary.Uvarint(claim.RootHash[len(claim.RootHash-8):])` + + // TODO_IMPROVE: add assertions about serviceId and appName and/or incorporate + // them into the scenarioState key(s). claim := claimsRes.Claim[0] require.Equal(s, accNameToAddrMap[supplierName], claim.SupplierAddress) } -func (s *suite) TheSupplierHasServicedASessionOfRelaysForApplication(supplierName string, appName string) { - // TODO_IN_THIS_COMMIT: use consts or something - // TODO_IN_THIS_COMMIT: use testclient.CometLocalWebsocketURL instead. - pocketNodeWebsocketUrl := "ws://poktroll-sequencer:36657/websocket" - msgClaimSenderQueryFmt := "tm.event='Tx' AND message.sender='%s'" - msgSenderQuery := fmt.Sprintf(msgClaimSenderQueryFmt, accNameToAddrMap[supplierName]) - s.Logf("msgSenderQuery: %s", msgSenderQuery) +func (s *suite) TheSupplierHasServicedASessionWithRelaysForServiceForApplication(supplierName, relayCountStr, serviceId, appName string) { ctx := context.Background() - // TODO_TECHDEBT: refactor to use EventsReplayClient once available. - eventsQueryClient := eventsquery.NewEventsQueryClient(pocketNodeWebsocketUrl) + relayCount, err := strconv.Atoi(relayCountStr) + require.NoError(s, err) + + // Query for any existing claims so that we can compensate for them in the + // future assertions about changes in on-chain claims. + claimsRes, err := s.supplierQueryClient.AllClaims(ctx, &suppliertypes.QueryAllClaimsRequest{}) + require.NoError(s, err) + s.scenarioState[preExistingClaimsKey] = claimsRes.Claim + + // Construct an events query client to listen for tx events from the supplier. + msgSenderQuery := fmt.Sprintf(msgClaimSenderQueryFmt, accNameToAddrMap[supplierName]) + + // TODO_TECHDEBT(#220): refactor to use EventsReplayClient once available. + eventsQueryClient := eventsquery.NewEventsQueryClient(testclient.CometLocalWebsocketURL) eitherEventsBzObs, err := eventsQueryClient.EventsBytes(ctx, msgSenderQuery) require.NoError(s, err) @@ -123,16 +134,14 @@ func (s *suite) TheSupplierHasServicedASessionOfRelaysForApplication(supplierNam eitherEventsBzRelayObs := channel.ToReplayObservable(ctx, eitherEventsReplayBufferSize, eitherEventsBytesObs) s.scenarioState[eitherEventsBzReplayObsKey] = eitherEventsBzRelayObs - // TODO_IN_THIS_COMMMIT: use consts or something s.sendRelaysForSession( appName, supplierName, - "anvil", - 5, + testServiceId, + relayCount, ) } -// TODO_IN_THIS_COMMIT: rename func (s *suite) sendRelaysForSession( appName string, supplierName string, @@ -143,7 +152,7 @@ func (s *suite) sendRelaysForSession( s.TheSupplierIsStakedForService(supplierName, serviceId) s.TheSessionForApplicationAndServiceContainsTheSupplier(appName, serviceId, supplierName) - // TODO_IN_THIS_COMMIT: something better + // TODO_IMPROVE/TODO_COMMUNITY: hard-code a default set of RPC calls to iterate over for coverage. data := `{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}` for i := 0; i < relayLimit; i++ { diff --git a/pkg/client/tx/client.go b/pkg/client/tx/client.go index 39f5208e0..f31de9532 100644 --- a/pkg/client/tx/client.go +++ b/pkg/client/tx/client.go @@ -89,7 +89,11 @@ type ( // the transactions subscription. type TxEvent struct { // Tx is the binary representation of the tx hash. - Tx []byte `json:"tx"` + Tx []byte `json:"tx"` + Result TxResult `json:"result"` +} + +type TxResult struct { Events []abciTypes.Event `json:"events"` } diff --git a/testutil/keeper/supplier.go b/testutil/keeper/supplier.go index 7bca935dc..8bd600c27 100644 --- a/testutil/keeper/supplier.go +++ b/testutil/keeper/supplier.go @@ -15,22 +15,14 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + "github.com/pokt-network/poktroll/testutil/supplier" "github.com/pokt-network/poktroll/testutil/supplier/mocks" - apptypes "github.com/pokt-network/poktroll/x/application/types" sessiontypes "github.com/pokt-network/poktroll/x/session/types" - sharedtypes "github.com/pokt-network/poktroll/x/shared/types" "github.com/pokt-network/poktroll/x/supplier/keeper" "github.com/pokt-network/poktroll/x/supplier/types" ) -type SessionMetaFixturesByAppAddr map[string]SessionMetaFixture -type SessionMetaFixture struct { - SessionId string - AppAddr string - SupplierAddr string -} - -func SupplierKeeper(t testing.TB, sessionFixtures SessionMetaFixturesByAppAddr) (*keeper.Keeper, sdk.Context) { +func SupplierKeeper(t testing.TB, sessionByAppAddr supplier.SessionsByAppAddress) (*keeper.Keeper, sdk.Context) { t.Helper() storeKey := sdk.NewKVStoreKey(types.StoreKey) @@ -58,27 +50,23 @@ func SupplierKeeper(t testing.TB, sessionFixtures SessionMetaFixturesByAppAddr) ctx sdk.Context, req *sessiontypes.QueryGetSessionRequest, ) (*sessiontypes.QueryGetSessionResponse, error) { - sessionMock, ok := sessionFixtures[req.GetApplicationAddress()] + session, ok := sessionByAppAddr[req.GetApplicationAddress()] require.Truef(t, ok, "application address not provided during mock construction: %q", req.ApplicationAddress) return &sessiontypes.QueryGetSessionResponse{ Session: &sessiontypes.Session{ Header: &sessiontypes.SessionHeader{ - ApplicationAddress: sessionMock.AppAddr, + ApplicationAddress: session.GetApplication().GetAddress(), Service: req.GetService(), SessionStartBlockHeight: 1, - SessionId: sessionMock.SessionId, + SessionId: session.GetSessionId(), SessionEndBlockHeight: 5, }, - SessionId: sessionMock.SessionId, + SessionId: session.GetSessionId(), SessionNumber: 1, - NumBlocksPerSession: 4, - Application: &apptypes.Application{ - Address: sessionMock.AppAddr, - }, - Suppliers: []*sharedtypes.Supplier{{ - Address: sessionMock.SupplierAddr, - }}, + NumBlocksPerSession: session.GetNumBlocksPerSession(), + Application: session.GetApplication(), + Suppliers: session.GetSuppliers(), }, }, nil }, diff --git a/testutil/network/network.go b/testutil/network/network.go index 724895947..11a5f18ab 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -126,8 +126,8 @@ func DefaultApplicationModuleGenesisState(t *testing.T, n int) *apptypes.Genesis return state } -// TODO_IN_THIS_COMMIT: fix comment... -// ApplicationModuleGenesisStateWithAccount generates a GenesisState object with a single supplier with the given address. +// ApplicationModuleGenesisStateWithAccount generates a GenesisState object with +// a single application for each of the given addresses. func ApplicationModuleGenesisStateWithAddresses(t *testing.T, addresses []string) *apptypes.GenesisState { t.Helper() state := apptypes.DefaultGenesis() @@ -194,7 +194,8 @@ func DefaultSupplierModuleGenesisState(t *testing.T, n int) *suppliertypes.Genes return state } -// SupplierModuleGenesisStateWithAccount generates a GenesisState object with a single supplier with the given address. +// SupplierModuleGenesisStateWithAddresses generates a GenesisState object with +// a single supplier for each of the given addresses. func SupplierModuleGenesisStateWithAddresses(t *testing.T, addresses []string) *suppliertypes.GenesisState { t.Helper() state := suppliertypes.DefaultGenesis() diff --git a/testutil/supplier/fixtures.go b/testutil/supplier/fixtures.go new file mode 100644 index 000000000..b3b425240 --- /dev/null +++ b/testutil/supplier/fixtures.go @@ -0,0 +1,112 @@ +package supplier + +import ( + "testing" + + sdktypes "github.com/cosmos/cosmos-sdk/types" + + apptypes "github.com/pokt-network/poktroll/x/application/types" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" +) + +const ( + testSessionNumber = 1 + testBlockHeight = 1 + testBlocksPerSession = 4 + testSessionId = "mock_session_id" +) + +// SessionsByAppAddress is a map of session fixtures where the key is the +// application address and the value is the session fixture. +type SessionsByAppAddress map[string]sessiontypes.Session + +// NewSessionFixturesWithPairings creates a map of session fixtures where the key +// is the application address and the value is the session fixture. App/supplier +// addresses are expected to be provided in alternating order (as pairs). The same +// app and/or supplier may be given more than once but only distinct pairs will +// be added to the session fixtures map. +func NewSessionFixturesWithPairings( + t *testing.T, + service *sharedtypes.Service, + appAndSupplierAddrPairs ...string, +) SessionsByAppAddress { + t.Helper() + + if len(appAndSupplierAddrPairs)%2 != 0 { + t.Fatalf("expected even number of app and supplier address pairs, got %d", len(appAndSupplierAddrPairs)) + } + + // Initialize the session fixtures map. + sessionFixturesByAppAddr := make(SessionsByAppAddress) + + // Iterate over the app and supplier address pairs (two indices at a time), + // and create a session fixture for each app address. + for i := 0; i < len(appAndSupplierAddrPairs); i += 2 { + appAddr := appAndSupplierAddrPairs[i] + application := newApplication(t, appAddr, service) + + supplierAddr := appAndSupplierAddrPairs[i+1] + supplier := newSupplier(t, supplierAddr, service) + + if session, ok := sessionFixturesByAppAddr[appAddr]; ok { + session.Suppliers = append(session.Suppliers, supplier) + continue + } + + sessionFixturesByAppAddr[appAddr] = sessiontypes.Session{ + Header: &sessiontypes.SessionHeader{ + ApplicationAddress: appAddr, + Service: service, + SessionStartBlockHeight: testBlockHeight, + SessionId: testSessionId, + SessionEndBlockHeight: testBlockHeight + testBlocksPerSession, + }, + SessionId: testSessionId, + SessionNumber: testSessionNumber, + NumBlocksPerSession: testBlocksPerSession, + Application: application, + Suppliers: []*sharedtypes.Supplier{ + newSupplier(t, supplierAddr, service), + }, + } + } + + return sessionFixturesByAppAddr +} + +func newSupplier(t *testing.T, addr string, services ...*sharedtypes.Service) *sharedtypes.Supplier { + t.Helper() + + serviceConfigs := make([]*sharedtypes.SupplierServiceConfig, len(services)) + for i, service := range services { + serviceConfigs[i] = &sharedtypes.SupplierServiceConfig{ + Service: service, + Endpoints: nil, + } + } + + return &sharedtypes.Supplier{ + Address: addr, + Stake: &sdktypes.Coin{}, + Services: serviceConfigs, + } +} + +func newApplication(t *testing.T, addr string, services ...*sharedtypes.Service) *apptypes.Application { + t.Helper() + + serviceConfigs := make([]*sharedtypes.ApplicationServiceConfig, len(services)) + for i, service := range services { + serviceConfigs[i] = &sharedtypes.ApplicationServiceConfig{ + Service: service, + } + } + + return &apptypes.Application{ + Address: addr, + Stake: &sdktypes.Coin{}, + ServiceConfigs: serviceConfigs, + DelegateeGatewayAddresses: nil, + } +} diff --git a/testutil/testkeyring/accounts.go b/testutil/testkeyring/accounts.go index ad96b8bda..6be540540 100644 --- a/testutil/testkeyring/accounts.go +++ b/testutil/testkeyring/accounts.go @@ -29,7 +29,6 @@ type PreGeneratedAccountIterator struct { // an error if the index is out of range. func PreGeneratedAccountAtIndex(index uint32) (*PreGeneratedAccount, error) { if preGeneratedAccounts.nextIndex >= uint32(len(preGeneratedAccounts.accounts)) { - // TODO_IN_THIS_COMMIT: refactor error... return nil, ErrPreGeneratedAccountIndexOutOfRange.Wrapf("%d", index) } diff --git a/x/supplier/client/cli/helpers_test.go b/x/supplier/client/cli/helpers_test.go index d6066c28a..fd6ea06b4 100644 --- a/x/supplier/client/cli/helpers_test.go +++ b/x/supplier/client/cli/helpers_test.go @@ -2,17 +2,39 @@ package cli_test import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" "strconv" "testing" + "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + types3 "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/testutil/cli" + types4 "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" "github.com/pokt-network/poktroll/cmd/pocketd/cmd" "github.com/pokt-network/poktroll/testutil/network" + "github.com/pokt-network/poktroll/testutil/testkeyring" + types5 "github.com/pokt-network/poktroll/x/application/types" + types2 "github.com/pokt-network/poktroll/x/session/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" + cli2 "github.com/pokt-network/poktroll/x/supplier/client/cli" "github.com/pokt-network/poktroll/x/supplier/types" ) +// TODO_TECHDEBT: This should not be hardcoded once the num blocks per session is configurable. +const ( + numBlocksPerSession = 4 + testServiceId = "svc1" +) + // Dummy variable to avoid unused import error. var _ = strconv.IntSize @@ -32,3 +54,195 @@ func networkWithSupplierObjects(t *testing.T, n int) (*network.Network, []shared cfg.GenesisState[types.ModuleName] = buf return network.New(t, cfg), supplierGenesisState.SupplierList } + +// TODO_CONSIDERATION: perhaps this (and/or other similar helpers) can be refactored +// into something more generic and moved into a shared testutil package. +// TODO_TECHDEBT: refactor; this function has more than a single responsibility, +// which should be to configure and start the test network. The genesis state, +// accounts, and claims set up logic can probably be factored out and/or reduced. +func networkWithClaimObjects( + t *testing.T, + sessionCount int, + supplierCount int, + appCount int, + // TODO_THIS_COMMIT: hook up to genesis state generation... + serviceCount int, +) (net *network.Network, claims []types.Claim) { + t.Helper() + + // Initialize a network config. + cfg := network.DefaultConfig() + + // Construct an in-memory keyring so that it can be populated and used prior + // to network start. + kr := keyring.NewInMemory(cfg.Codec) + // Populate the in-memmory keyring with as many pre-generated accounts as + // we expect to need for the test (i.e. appCount + supplierCount). + testkeyring.CreatePreGeneratedKeyringAccounts(t, kr, supplierCount+appCount) + + // Use the pre-generated accounts iterator to populate the supplier and + // application accounts and addresses lists for use in genesis state construction. + preGeneratedAccts := testkeyring.PreGeneratedAccounts().Clone() + + // Create a supplier for each session in numClaimsSessions and an app for each + // claim in numClaimsPerSession. + supplierAccts := make([]*testkeyring.PreGeneratedAccount, supplierCount) + supplierAddrs := make([]string, supplierCount) + for i := range supplierAccts { + account := preGeneratedAccts.MustNext() + supplierAccts[i] = account + supplierAddrs[i] = account.Address.String() + } + appAccts := make([]*testkeyring.PreGeneratedAccount, appCount) + appAddrs := make([]string, appCount) + for i := range appAccts { + account := preGeneratedAccts.MustNext() + appAccts[i] = account + appAddrs[i] = account.Address.String() + } + + // Construct supplier and application module genesis states given the account addresses. + supplierGenesisState := network.SupplierModuleGenesisStateWithAddresses(t, supplierAddrs) + supplierGenesisBuffer, err := cfg.Codec.MarshalJSON(supplierGenesisState) + require.NoError(t, err) + appGenesisState := network.ApplicationModuleGenesisStateWithAddresses(t, appAddrs) + appGenesisBuffer, err := cfg.Codec.MarshalJSON(appGenesisState) + require.NoError(t, err) + + // Add supplier and application module genesis states to the network config. + cfg.GenesisState[types.ModuleName] = supplierGenesisBuffer + cfg.GenesisState[types5.ModuleName] = appGenesisBuffer + + // Construct the network with the configuration. + net = network.New(t, cfg) + // Only the first validator's client context is populated. + // (see: https://pkg.go.dev/github.com/cosmos/cosmos-sdk/testutil/network#pkg-overview) + ctx := net.Validators[0].ClientCtx + // Overwrite the client context's keyring with the in-memory one that contains + // our pre-generated accounts. + ctx = ctx.WithKeyring(kr) + + // Initialize all the accounts + sequenceIndex := 1 + for _, supplierAcct := range supplierAccts { + network.InitAccountWithSequence(t, net, supplierAcct.Address, sequenceIndex) + sequenceIndex++ + } + for _, appAcct := range appAccts { + network.InitAccountWithSequence(t, net, appAcct.Address, sequenceIndex) + sequenceIndex++ + } + // need to wait for the account to be initialized in the next block + require.NoError(t, net.WaitForNextBlock()) + + // Create sessionCount * numClaimsPerSession claims for the supplier + sessionEndHeight := int64(1) + for sessionIdx := 0; sessionIdx < sessionCount; sessionIdx++ { + sessionEndHeight += numBlocksPerSession + for _, appAcct := range appAccts { + for _, supplierAcct := range supplierAccts { + claim := createClaim( + t, net, ctx, + supplierAcct.Address.String(), + sessionEndHeight, + appAcct.Address.String(), + ) + claims = append(claims, *claim) + // TODO_TECHDEBT(#196): Move this outside of the forloop so that the test iteration is faster + require.NoError(t, net.WaitForNextBlock()) + } + } + } + + return net, claims +} + +func encodeSessionHeader( + t *testing.T, + appAddr string, + sessionId string, + sessionStartHeight int64, +) string { + t.Helper() + + argSessionHeader := &types2.SessionHeader{ + ApplicationAddress: appAddr, + SessionStartBlockHeight: sessionStartHeight, + SessionId: sessionId, + SessionEndBlockHeight: sessionStartHeight + numBlocksPerSession, + Service: &sharedtypes.Service{Id: testServiceId}, + } + cdc := codec.NewProtoCodec(types3.NewInterfaceRegistry()) + sessionHeaderBz := cdc.MustMarshalJSON(argSessionHeader) + return base64.StdEncoding.EncodeToString(sessionHeaderBz) +} + +func createClaim( + t *testing.T, + net *network.Network, + ctx client.Context, + supplierAddr string, + sessionEndHeight int64, + appAddress string, +) *types.Claim { + t.Helper() + + rootHash := []byte("root_hash") + sessionStartHeight := sessionEndHeight - numBlocksPerSession + sessionId := getSessionId(t, net, appAddress, supplierAddr, sessionStartHeight) + sessionHeaderEncoded := encodeSessionHeader(t, appAddress, sessionId, sessionStartHeight) + rootHashEncoded := base64.StdEncoding.EncodeToString(rootHash) + + args := []string{ + sessionHeaderEncoded, + rootHashEncoded, + fmt.Sprintf("--%s=%s", flags.FlagFrom, supplierAddr), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, types4.NewCoins(types4.NewCoin(net.Config.BondDenom, math.NewInt(10))).String()), + } + + responseRaw, err := cli.ExecTestCLICmd(ctx, cli2.CmdCreateClaim(), args) + require.NoError(t, err) + var responseJson map[string]interface{} + err = json.Unmarshal(responseRaw.Bytes(), &responseJson) + require.NoError(t, err) + require.Equal(t, float64(0), responseJson["code"], "code is not 0 in the response: %v", responseJson) + + return &types.Claim{ + SupplierAddress: supplierAddr, + SessionId: sessionId, + SessionEndBlockHeight: uint64(sessionEndHeight), + RootHash: rootHash, + } +} + +func getSessionId( + t *testing.T, + net *network.Network, + appAddr string, + supplierAddr string, + sessionStartHeight int64, +) string { + t.Helper() + ctx := context.TODO() + + sessionQueryClient := types2.NewQueryClient(net.Validators[0].ClientCtx) + res, err := sessionQueryClient.GetSession(ctx, &types2.QueryGetSessionRequest{ + ApplicationAddress: appAddr, + Service: &sharedtypes.Service{Id: testServiceId}, + BlockHeight: sessionStartHeight, + }) + require.NoError(t, err) + + var found bool + for _, supplier := range res.GetSession().GetSuppliers() { + if supplier.GetAddress() == supplierAddr { + found = true + break + } + } + require.Truef(t, found, "supplier address %s not found in session", supplierAddr) + + return res.Session.SessionId +} diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index 9dbd367da..6e5730e0d 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -1,238 +1,26 @@ package cli_test import ( - "context" - "encoding/base64" - "encoding/json" "fmt" "testing" - sdkmath "cosmossdk.io/math" tmcli "github.com/cometbft/cometbft/libs/cli" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec" - cdctypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/keyring" clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/pokt-network/poktroll/testutil/network" "github.com/pokt-network/poktroll/testutil/nullify" - "github.com/pokt-network/poktroll/testutil/testkeyring" - apptypes "github.com/pokt-network/poktroll/x/application/types" - sessiontypes "github.com/pokt-network/poktroll/x/session/types" - sharedtypes "github.com/pokt-network/poktroll/x/shared/types" "github.com/pokt-network/poktroll/x/supplier/client/cli" "github.com/pokt-network/poktroll/x/supplier/types" ) -// TODO_TECHDEBT: This should not be hardcoded once the num blocks per session is configurable -const numBlocksPerSession = 4 - -func encodeSessionHeader( - t *testing.T, - appAddr string, - sessionId string, - sessionStartHeight int64, -) string { - t.Helper() - - argSessionHeader := &sessiontypes.SessionHeader{ - ApplicationAddress: appAddr, - SessionStartBlockHeight: sessionStartHeight, - SessionId: sessionId, - SessionEndBlockHeight: sessionStartHeight + numBlocksPerSession, - Service: &sharedtypes.Service{Id: "svc1"}, - } - cdc := codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) - sessionHeaderBz := cdc.MustMarshalJSON(argSessionHeader) - return base64.StdEncoding.EncodeToString(sessionHeaderBz) -} - -func createClaim( - t *testing.T, - net *network.Network, - ctx client.Context, - supplierAddr string, - sessionEndHeight int64, - appAddress string, -) *types.Claim { - t.Helper() - - //appAddr := sample.AccAddress() - rootHash := []byte("root_hash") - sessionStartHeight := sessionEndHeight - numBlocksPerSession - sessionId, err := getSessionId(t, net, appAddress, supplierAddr, sessionStartHeight) - require.NoError(t, err) - sessionHeaderEncoded := encodeSessionHeader(t, appAddress, sessionId, sessionStartHeight) - rootHashEncoded := base64.StdEncoding.EncodeToString(rootHash) - - args := []string{ - sessionHeaderEncoded, - rootHashEncoded, - fmt.Sprintf("--%s=%s", flags.FlagFrom, supplierAddr), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(net.Config.BondDenom, sdkmath.NewInt(10))).String()), - } - - responseRaw, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdCreateClaim(), args) - require.NoError(t, err) - var responseJson map[string]interface{} - err = json.Unmarshal(responseRaw.Bytes(), &responseJson) - require.NoError(t, err) - require.Equal(t, float64(0), responseJson["code"], "code is not 0 in the response: %v", responseJson) - - return &types.Claim{ - SupplierAddress: supplierAddr, - SessionId: sessionId, - SessionEndBlockHeight: uint64(sessionEndHeight), - RootHash: rootHash, - } -} - -func getSessionId( - t *testing.T, - net *network.Network, - appAddr string, - supplierAddr string, - sessionStartHeight int64, -) (string, error) { - t.Helper() - ctx := context.TODO() - - sessionQueryClient := sessiontypes.NewQueryClient(net.Validators[0].ClientCtx) - res, err := sessionQueryClient.GetSession(ctx, &sessiontypes.QueryGetSessionRequest{ - ApplicationAddress: appAddr, - Service: &sharedtypes.Service{Id: "svc1"}, // hardcoded for simplicity - BlockHeight: sessionStartHeight, - }) - if err != nil { - return "", err - } - - var found bool - for _, supplier := range res.GetSession().GetSuppliers() { - if supplier.GetAddress() == supplierAddr { - found = true - break - } - } - require.Truef(t, found, "supplier address %s not found in session", supplierAddr) - - return res.Session.SessionId, nil -} - -// TODO_CONSIDERATION: perhaps this (and/or other similar helpers) can be refactored -// into something more generic and moved into a shared testutil package. -func networkWithClaimObjects( - t *testing.T, - sessionCount int, - supplierCount int, - appCount int, - // TODO_THIS_COMMIT: hook up to genesis state generation... - serviceCount int, -) (net *network.Network, claims []types.Claim) { - t.Helper() - - // Initialize a network config. - cfg := network.DefaultConfig() - - // Construct an in-memory keyring so that it can be populated and used prior - // to network start. - kr := keyring.NewInMemory(cfg.Codec) - // Populate the in-memmory keyring with as many pre-generated accounts as - // we expect to need for the test. - testkeyring.CreatePreGeneratedKeyringAccounts(t, kr, 20) - - // Use the pre-generated accounts iterator to populate the supplier and - // application accounts and addresses lists for use in genesis state construction. - preGeneratedAccts := testkeyring.PreGeneratedAccounts().Clone() - - // Create a supplier for each session in numClaimsSessions and an app for each - // claim in numClaimsPerSession. - supplierAccts := make([]*testkeyring.PreGeneratedAccount, supplierCount) - supplierAddrs := make([]string, supplierCount) - for i := range supplierAccts { - account := preGeneratedAccts.MustNext() - supplierAccts[i] = account - supplierAddrs[i] = account.Address.String() - } - appAccts := make([]*testkeyring.PreGeneratedAccount, appCount) - appAddrs := make([]string, appCount) - for i := range appAccts { - account := preGeneratedAccts.MustNext() - appAccts[i] = account - appAddrs[i] = account.Address.String() - } - - // Construct supplier and application module genesis states given the account addresses. - supplierGenesisState := network.SupplierModuleGenesisStateWithAddresses(t, supplierAddrs) - supplierGenesisBuffer, err := cfg.Codec.MarshalJSON(supplierGenesisState) - require.NoError(t, err) - appGenesisState := network.ApplicationModuleGenesisStateWithAddresses(t, appAddrs) - appGenesisBuffer, err := cfg.Codec.MarshalJSON(appGenesisState) - require.NoError(t, err) - - // Add supplier and application module genesis states to the network config. - cfg.GenesisState[types.ModuleName] = supplierGenesisBuffer - cfg.GenesisState[apptypes.ModuleName] = appGenesisBuffer - - // Construct the network with the configuration. - net = network.New(t, cfg) - // Only the first validator's client context is populated. - // (see: https://pkg.go.dev/github.com/cosmos/cosmos-sdk/testutil/network#pkg-overview) - ctx := net.Validators[0].ClientCtx - // Overwrite the client context's keyring with the in-memory one that contains - // our pre-generated accounts. - ctx = ctx.WithKeyring(kr) - - // Initialize all the accounts - sequenceIndex := 1 - for _, supplierAcct := range supplierAccts { - network.InitAccountWithSequence(t, net, supplierAcct.Address, sequenceIndex) - sequenceIndex++ - } - for _, appAcct := range appAccts { - network.InitAccountWithSequence(t, net, appAcct.Address, sequenceIndex) - sequenceIndex++ - } - // need to wait for the account to be initialized in the next block - require.NoError(t, net.WaitForNextBlock()) - - // Create sessionCount * numClaimsPerSession claims for the supplier - sessionEndHeight := int64(1) - for sessionIdx := 0; sessionIdx < sessionCount; sessionIdx++ { - sessionEndHeight += numBlocksPerSession - // TODO_IN_THIS_COMMIT: numClaimsPerSession == supplierCount * appCount - for _, supplierAcct := range supplierAccts { - for _, appAcct := range appAccts { - claim := createClaim( - t, net, ctx, - supplierAcct.Address.String(), - sessionEndHeight, - appAcct.Address.String(), - ) - claims = append(claims, *claim) - // TODO_TECHDEBT(#196): Move this outside of the forloop so that the test iteration is faster - require.NoError(t, net.WaitForNextBlock()) - } - } - } - - return net, claims -} - func TestClaim_Show(t *testing.T) { sessionCount := 1 supplierCount := 3 appCount := 3 serviceCount := 1 - //numClaimsPerSession := supplierCount * appCount * serviceCount net, claims := networkWithClaimObjects( t, sessionCount, diff --git a/x/supplier/keeper/msg_server_create_claim.go b/x/supplier/keeper/msg_server_create_claim.go index 6112719e9..ce9a6e94a 100644 --- a/x/supplier/keeper/msg_server_create_claim.go +++ b/x/supplier/keeper/msg_server_create_claim.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "log" sdk "github.com/cosmos/cosmos-sdk/types" @@ -17,15 +18,24 @@ func (k msgServer) CreateClaim(goCtx context.Context, msg *suppliertypes.MsgCrea return nil, err } - sessionRes, err := k.Keeper.sessionKeeper.GetSession(goCtx, &sessiontypes.QueryGetSessionRequest{ - ApplicationAddress: msg.SessionHeader.ApplicationAddress, - Service: msg.SessionHeader.Service, - BlockHeight: msg.SessionHeader.SessionStartBlockHeight, - }) + sessionReq := &sessiontypes.QueryGetSessionRequest{ + ApplicationAddress: msg.GetSessionHeader().GetApplicationAddress(), + Service: msg.GetSessionHeader().GetService(), + BlockHeight: msg.GetSessionHeader().GetSessionStartBlockHeight(), + } + sessionRes, err := k.Keeper.sessionKeeper.GetSession(goCtx, sessionReq) if err != nil { return nil, err } + logger. + With( + "session_id", sessionRes.GetSession().GetSessionId(), + "session_end_height", msg.GetSessionHeader().GetSessionEndBlockHeight(), + "supplier", msg.GetSupplierAddress(), + ). + Debug("got sessionId for claim") + if sessionRes.Session.SessionId != msg.SessionHeader.SessionId { return nil, suppliertypes.ErrSupplierInvalidSessionId.Wrapf( "claimed sessionRes ID does not match on-chain sessionRes ID; expected %q, got %q", @@ -36,7 +46,7 @@ func (k msgServer) CreateClaim(goCtx context.Context, msg *suppliertypes.MsgCrea var found bool for _, supplier := range sessionRes.GetSession().GetSuppliers() { - if supplier.Address == msg.SupplierAddress { + if supplier.Address == msg.GetSupplierAddress() { found = true break } @@ -45,11 +55,22 @@ func (k msgServer) CreateClaim(goCtx context.Context, msg *suppliertypes.MsgCrea if !found { return nil, suppliertypes.ErrSupplierNotFound.Wrapf( "supplier address %q in session ID %q", - msg.SupplierAddress, + msg.GetSupplierAddress(), sessionRes.GetSession().GetSessionId(), ) } + // TODO_TECHDEBT(#181): refactor once structured logging is available. + log.Printf("DEBUG: validated claim with sessionId %q for supplier %q", sessionRes.Session.SessionId, msg.GetSupplierAddress()) + + logger. + With( + "session_id", sessionRes.GetSession().GetSessionId(), + "session_end_height", msg.GetSessionHeader().GetSessionEndBlockHeight(), + "supplier", msg.GetSupplierAddress(), + ). + Debug("validated claim") + /* TODO_INCOMPLETE: @@ -64,14 +85,21 @@ func (k msgServer) CreateClaim(goCtx context.Context, msg *suppliertypes.MsgCrea // Construct and insert claim after all validation. claim := suppliertypes.Claim{ - SupplierAddress: msg.SupplierAddress, - SessionId: msg.SessionHeader.SessionId, - SessionEndBlockHeight: uint64(msg.SessionHeader.SessionEndBlockHeight), + SupplierAddress: msg.GetSupplierAddress(), + SessionId: msg.GetSessionHeader().GetSessionId(), + SessionEndBlockHeight: uint64(msg.GetSessionHeader().GetSessionEndBlockHeight()), RootHash: msg.RootHash, } k.Keeper.InsertClaim(ctx, claim) - logger.Info("created claim for supplier %s at sessionRes ending height %d", claim.SupplierAddress, claim.SessionEndBlockHeight) + logger. + With( + "session_id", claim.GetSessionId(), + "session_end_height", claim.GetSessionEndBlockHeight(), + "supplier", claim.GetSupplierAddress(), + ). + Debug("created claim") + // TODO_CONSIDERATION: perhaps it would be useful to return the claim in the response. return &suppliertypes.MsgCreateClaimResponse{}, nil } diff --git a/x/supplier/keeper/msg_server_create_claim_test.go b/x/supplier/keeper/msg_server_create_claim_test.go index 7c0d81ebc..d0deaa0ad 100644 --- a/x/supplier/keeper/msg_server_create_claim_test.go +++ b/x/supplier/keeper/msg_server_create_claim_test.go @@ -8,6 +8,7 @@ import ( keepertest "github.com/pokt-network/poktroll/testutil/keeper" "github.com/pokt-network/poktroll/testutil/sample" + "github.com/pokt-network/poktroll/testutil/supplier" sessiontypes "github.com/pokt-network/poktroll/x/session/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" "github.com/pokt-network/poktroll/x/supplier/keeper" @@ -15,19 +16,14 @@ import ( suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" ) +const testServiceId = "svc1" + func TestMsgServer_CreateClaim_Success(t *testing.T) { appAddr, supplierAddr := sample.AccAddress(), sample.AccAddress() + service := &sharedtypes.Service{Id: testServiceId} + sessionFixturesByAddr := supplier.NewSessionFixturesWithPairings(t, service, appAddr, supplierAddr) - // TODO_IN_THIS_COMMIT: dedup & refactor to a test helper. - sessionMockMap := keepertest.SessionMetaFixturesByAppAddr{ - appAddr: keepertest.SessionMetaFixture{ - SessionId: "mock_session_id", - AppAddr: appAddr, - SupplierAddr: supplierAddr, - }, - } - - supplierKeeper, sdkCtx := keepertest.SupplierKeeper(t, sessionMockMap) + supplierKeeper, sdkCtx := keepertest.SupplierKeeper(t, sessionFixturesByAddr) srv := keeper.NewMsgServerImpl(*supplierKeeper) ctx := sdk.WrapSDKContext(sdkCtx) @@ -51,17 +47,11 @@ func TestMsgServer_CreateClaim_Success(t *testing.T) { } func TestMsgServer_CreateClaim_Error(t *testing.T) { + service := &sharedtypes.Service{Id: testServiceId} appAddr, supplierAddr := sample.AccAddress(), sample.AccAddress() + sessionFixturesByAppAddr := supplier.NewSessionFixturesWithPairings(t, service, appAddr, supplierAddr) - // TODO_IN_THIS_COMMIT: dedup & refactor to a test helper. - sessionMockMap := keepertest.SessionMetaFixturesByAppAddr{ - appAddr: keepertest.SessionMetaFixture{ - SessionId: "mock_session_id", - AppAddr: appAddr, - SupplierAddr: supplierAddr, - }, - } - supplierKeeper, sdkCtx := keepertest.SupplierKeeper(t, sessionMockMap) + supplierKeeper, sdkCtx := keepertest.SupplierKeeper(t, sessionFixturesByAppAddr) srv := keeper.NewMsgServerImpl(*supplierKeeper) ctx := sdk.WrapSDKContext(sdkCtx) From 79fdefa07208cfd319434ee05c3e97d6d0395943 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 4 Dec 2023 11:22:14 +0100 Subject: [PATCH 19/33] chore: add TODO Co-authored-by: Daniel Olshansky --- x/supplier/keeper/keeper.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/supplier/keeper/keeper.go b/x/supplier/keeper/keeper.go index 8e378d511..709c94c30 100644 --- a/x/supplier/keeper/keeper.go +++ b/x/supplier/keeper/keeper.go @@ -51,6 +51,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } +// TODO_TECHDEBT: Evaluate if this is still necessary after the upgrade to cosmos 0.5x // SupplySessionKeeper assigns the session keeper dependency of this supplier // keeper. This MUST be done as a separate step from construction because there // is a circular dependency between the supplier and session keepers. From 7c08f69d8e04efaa1748c8b19d3d97404d2a5fdd Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 4 Dec 2023 11:56:35 +0100 Subject: [PATCH 20/33] fixup! chore: update mock node flag with in-tilt host --- testutil/testclient/localnet.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testutil/testclient/localnet.go b/testutil/testclient/localnet.go index a11578ae1..d83969f21 100644 --- a/testutil/testclient/localnet.go +++ b/testutil/testclient/localnet.go @@ -16,7 +16,7 @@ import ( // // TODO_IMPROVE: It would be nice if the value could be set correctly based // on whether the test using it is running in tilt or not. -const CometLocalWebsocketURL = "ws://poktroll-sequencer:36657/websocket" +const CometLocalWebsocketURL = "ws://sequencer-poktroll-sequencer:36657/websocket" // EncodingConfig encapsulates encoding configurations for the Pocket application. var EncodingConfig = app.MakeEncodingConfig() @@ -67,7 +67,7 @@ func NewLocalnetFlagSet(t gocuke.TestingT) *pflag.FlagSet { mockFlagSet := pflag.NewFlagSet("test", pflag.ContinueOnError) // TODO_IMPROVE: It would be nice if the value could be set correctly based // on whether the test using it is running in tilt or not. - mockFlagSet.String(flags.FlagNode, "tcp://poktroll-sequencer:36657", "use localnet poktrolld node") + mockFlagSet.String(flags.FlagNode, "tcp://sequencer-poktroll-sequencer:36657", "use localnet poktrolld node") mockFlagSet.String(flags.FlagHome, "", "use localnet poktrolld node") mockFlagSet.String(flags.FlagKeyringBackend, "test", "use test keyring") err := mockFlagSet.Parse([]string{}) From 7ab73a921ce462678b0ceb8b484e92168867edbf Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 4 Dec 2023 12:24:51 +0100 Subject: [PATCH 21/33] chore: review feedback improvements --- Makefile | 6 +- testutil/testkeyring/accounts.go | 100 ++++++++---------- testutil/testkeyring/accounts_table.go | 2 +- testutil/testkeyring/gen_accounts/gen.go | 14 +-- testutil/testkeyring/gen_accounts/template.go | 2 +- 5 files changed, 51 insertions(+), 73 deletions(-) diff --git a/Makefile b/Makefile index a3660cd25..c7d1d1c25 100644 --- a/Makefile +++ b/Makefile @@ -173,12 +173,12 @@ go_mockgen: ## Use `mockgen` to generate mocks used for testing purposes of all go generate ./pkg/relayer/interface.go go generate ./pkg/crypto/rings/interface.go -.PHONY: go_fixturegen +.PHONY: go_testgen_fixtures go_fixturegen: ## Generate fixture data for unit tests go generate ./pkg/relayer/miner/miner_test.go -.PHONY: go_test_accountgen -go_test_accountgen: ## Generate test accounts for usage in test environments +.PHONY: go_testgen_accounts +go_testgen_accounts: ## Generate test accounts for usage in test environments go generate ./testutil/testkeyring/keyring.go .PHONY: go_develop diff --git a/testutil/testkeyring/accounts.go b/testutil/testkeyring/accounts.go index 6be540540..c5523ef43 100644 --- a/testutil/testkeyring/accounts.go +++ b/testutil/testkeyring/accounts.go @@ -5,48 +5,51 @@ import ( "encoding/json" "sync/atomic" - errorsmod "cosmossdk.io/errors" - "github.com/cosmos/cosmos-sdk/testutil" sdktypes "github.com/cosmos/cosmos-sdk/types" ) -var ( - ErrPreGeneratedAccountIndexOutOfRange = errorsmod.New(codespace, 1, "index out of range of pre-generated accounts list") - codespace = "testutil/network" -) - +// PreGeneratedAccount holds the address and mnemonic of an account which was +// pre-generated by the `gen_accounts` package. It is intended to be used ONLY +// in tests. It is useful for scenarios where it is necessary to know the address +// of a specific key in a separate context from that of keyring and/or module +// genesis state construction. type PreGeneratedAccount struct { Address sdktypes.AccAddress Mnemonic string } +// PreGeneratedAccountIterator is an iterator over the pre-generated accounts. +// A new iterator populated with existing pre-generated accounts can be created +// with the PreGeneratedAccounts function. Alternatively, a new iterator can be +// created with the NewPreGeneratedAccountIterator function, to which a list of +// pre-generated accounts to be iterated over must be provided. type PreGeneratedAccountIterator struct { accounts []*PreGeneratedAccount nextIndex uint32 } -// PreGeneratedAccountAtIndex returns the account at the given index. It returns -// an error if the index is out of range. -func PreGeneratedAccountAtIndex(index uint32) (*PreGeneratedAccount, error) { +// PreGeneratedAccountAtIndex returns the pre-generated account at the given index. +// It returns nil and false if the index is out of range. +func PreGeneratedAccountAtIndex(index uint32) (_ *PreGeneratedAccount, ok bool) { if preGeneratedAccounts.nextIndex >= uint32(len(preGeneratedAccounts.accounts)) { - return nil, ErrPreGeneratedAccountIndexOutOfRange.Wrapf("%d", index) + return nil, false } - return preGeneratedAccounts.accounts[index], nil + return preGeneratedAccounts.accounts[index], true } -// MustPreGeneratedAccountAtIndex returns the account at the given index. It -// panics on error; i.e. if the index is out of range. +// MustPreGeneratedAccountAtIndex returns the pre-generated account at the given index. +// It panics on error; i.e. if the index is out of range. func MustPreGeneratedAccountAtIndex(index uint32) *PreGeneratedAccount { - account, err := PreGeneratedAccountAtIndex(index) - if err != nil { - panic(err) + account, ok := PreGeneratedAccountAtIndex(index) + if !ok { + panic("index out of range of pre-generated accounts list") } return account } // PreGeneratedAccounts returns a new PreGeneratedAccountIterator with the -// accounts which were pre-generated by the `gen_accounts` tool. +// accounts which were pre-generated by the `gen_accounts` tool (i.e. accounts_table.go). func PreGeneratedAccounts() *PreGeneratedAccountIterator { return preGeneratedAccounts.Clone() } @@ -61,31 +64,20 @@ func NewPreGeneratedAccountIterator(accounts ...*PreGeneratedAccount) *PreGenera } } -// MustNext returns the next account in the iterator. It panics if it encounters -// an error. It is safe to call concurrently and is guaranteed to return a unique -// -// account on each call. -func (iter *PreGeneratedAccountIterator) MustNext() *PreGeneratedAccount { - next, err := iter.Next() - if err != nil { - panic(err) - } - return next -} - // Next returns the next account in the iterator. It is safe to call // concurrently and is guaranteed to return a unique account on each call. -func (iter *PreGeneratedAccountIterator) Next() (*PreGeneratedAccount, error) { +// If the iterator index goes out of range, it returns nil and false. +func (iter *PreGeneratedAccountIterator) Next() (_ *PreGeneratedAccount, ok bool) { // NB: instead of loading and incrementing in separate steps, just increment // and use nextIndex-1 for the current index. nextIndex := atomic.AddUint32(&iter.nextIndex, 1) currentIndex := nextIndex - 1 if currentIndex > uint32(len(iter.accounts)) { - return nil, ErrPreGeneratedAccountIndexOutOfRange.Wrapf("%d", currentIndex) + return nil, false } - return iter.accounts[currentIndex], nil + return iter.accounts[currentIndex], true } // Clone returns a new PreGeneratedAccountIterator with the same accounts as the @@ -94,35 +86,33 @@ func (iter *PreGeneratedAccountIterator) Clone() *PreGeneratedAccountIterator { return NewPreGeneratedAccountIterator(iter.accounts...) } -func (pga *PreGeneratedAccount) ToTestAccount(name ...string) testutil.TestAccount { - return testutil.TestAccount{ - Name: name[0], - Address: pga.Address, - } -} - -// mustParsePreGeneratedAccount parses the given base64 and JSON encoded account -// string into a PreGeneratedAccount. It panics on error. -func mustParsePreGeneratedAccount(accountStr string) *PreGeneratedAccount { - account, err := parsePreGeneratedAccount(accountStr) +// Marshal returns the base64 and JSON encoded account string. +func (pga *PreGeneratedAccount) Marshal() (string, error) { + accountJson, err := json.Marshal(pga) if err != nil { - panic(err) + return "", err } - return account + + accountStr := base64.StdEncoding.EncodeToString(accountJson) + return accountStr, nil } -// parsePreGeneratedAccount parses the given base64 and JSON encoded account string -// into a PreGeneratedAccount. -func parsePreGeneratedAccount(accountStr string) (*PreGeneratedAccount, error) { +// UnmarshalString parses the given base64 and JSON encoded account string into +// the PreGeneratedAccount receiver. +func (pga *PreGeneratedAccount) UnmarshalString(accountStr string) error { accountJson, err := base64.StdEncoding.DecodeString(accountStr) if err != nil { - return nil, err + return err } + return json.Unmarshal(accountJson, pga) +} - preGeneratedAccount := new(PreGeneratedAccount) - if err := json.Unmarshal(accountJson, preGeneratedAccount); err != nil { - return nil, err +// mustParsePreGeneratedAccount parses the given base64 and JSON encoded account +// string into a PreGeneratedAccount. It panics on error. +func mustParsePreGeneratedAccount(accountStr string) *PreGeneratedAccount { + account := new(PreGeneratedAccount) + if err := account.UnmarshalString(accountStr); err != nil { + panic(err) } - - return preGeneratedAccount, nil + return account } diff --git a/testutil/testkeyring/accounts_table.go b/testutil/testkeyring/accounts_table.go index 108a8c7fb..711a25018 100644 --- a/testutil/testkeyring/accounts_table.go +++ b/testutil/testkeyring/accounts_table.go @@ -1,7 +1,7 @@ // DO NOT EDIT. This Code is generated by gen_accounts/gen.go, // changes will be overwritten upon regeneration. // -// To regenerate this file, use make go_test_accountgen or go generate ./testutil/network/keyring.go. +// To regenerate this file, use make go_testgen_accounts or go generate ./testutil/network/keyring.go. package testkeyring diff --git a/testutil/testkeyring/gen_accounts/gen.go b/testutil/testkeyring/gen_accounts/gen.go index ca7c1549f..1a977ad88 100644 --- a/testutil/testkeyring/gen_accounts/gen.go +++ b/testutil/testkeyring/gen_accounts/gen.go @@ -4,8 +4,6 @@ package main import ( "bytes" - "encoding/base64" - "encoding/json" "flag" "fmt" "log" @@ -56,7 +54,7 @@ func main() { Mnemonic: mnemonic, } - preGeneratedAccountStr, err := serializePreGeneratedAccount(preGeneratedAccount) + preGeneratedAccountStr, err := preGeneratedAccount.Marshal() if err != nil { log.Fatal(err) } @@ -79,13 +77,3 @@ func main() { log.Fatal(err) } } - -func serializePreGeneratedAccount(account *testkeyring.PreGeneratedAccount) (string, error) { - accountJson, err := json.Marshal(account) - if err != nil { - return "", err - } - - accountStr := base64.StdEncoding.EncodeToString(accountJson) - return accountStr, nil -} diff --git a/testutil/testkeyring/gen_accounts/template.go b/testutil/testkeyring/gen_accounts/template.go index 522907034..7d1ce91ec 100644 --- a/testutil/testkeyring/gen_accounts/template.go +++ b/testutil/testkeyring/gen_accounts/template.go @@ -11,7 +11,7 @@ var ( `// DO NOT EDIT. This Code is generated by gen_accounts/gen.go, // changes will be overwritten upon regeneration. // -// To regenerate this file, use make go_test_accountgen or go generate ./testutil/network/keyring.go. +// To regenerate this file, use make go_testgen_accounts or go generate ./testutil/network/keyring.go. package testkeyring From 2361013d85c7bbad9a96147eed83494ba895583e Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 4 Dec 2023 12:36:17 +0100 Subject: [PATCH 22/33] chore: review feedback improvements Co-authored-by: Daniel Olshansky --- testutil/testkeyring/accounts.go | 12 ++++++------ testutil/testkeyring/gen_accounts/gen.go | 2 +- testutil/testkeyring/gen_accounts/template.go | 2 +- testutil/testkeyring/keyring.go | 4 ++++ 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/testutil/testkeyring/accounts.go b/testutil/testkeyring/accounts.go index c5523ef43..f71fe665d 100644 --- a/testutil/testkeyring/accounts.go +++ b/testutil/testkeyring/accounts.go @@ -14,8 +14,8 @@ import ( // of a specific key in a separate context from that of keyring and/or module // genesis state construction. type PreGeneratedAccount struct { - Address sdktypes.AccAddress - Mnemonic string + Address sdktypes.AccAddress `json:"address"` + Mnemonic string `json:"mnemonic"` } // PreGeneratedAccountIterator is an iterator over the pre-generated accounts. @@ -49,13 +49,13 @@ func MustPreGeneratedAccountAtIndex(index uint32) *PreGeneratedAccount { } // PreGeneratedAccounts returns a new PreGeneratedAccountIterator with the -// accounts which were pre-generated by the `gen_accounts` tool (i.e. accounts_table.go). +// accounts which were pre-generated by the `gen_accounts` package (i.e. accounts_table.go). func PreGeneratedAccounts() *PreGeneratedAccountIterator { return preGeneratedAccounts.Clone() } // NewPreGeneratedAccountIterator returns a new PreGeneratedAccountIterator with -// the given accounts. It is primarily used by the generated code to intially +// the given accounts. It is primarily used by the generated code to initially // construct the preGeneratedAccounts variable. func NewPreGeneratedAccountIterator(accounts ...*PreGeneratedAccount) *PreGeneratedAccountIterator { return &PreGeneratedAccountIterator{ @@ -99,8 +99,8 @@ func (pga *PreGeneratedAccount) Marshal() (string, error) { // UnmarshalString parses the given base64 and JSON encoded account string into // the PreGeneratedAccount receiver. -func (pga *PreGeneratedAccount) UnmarshalString(accountStr string) error { - accountJson, err := base64.StdEncoding.DecodeString(accountStr) +func (pga *PreGeneratedAccount) UnmarshalString(encodedAccountStr string) error { + accountJson, err := base64.StdEncoding.DecodeString(encodedAccountStr) if err != nil { return err } diff --git a/testutil/testkeyring/gen_accounts/gen.go b/testutil/testkeyring/gen_accounts/gen.go index 1a977ad88..03709bb21 100644 --- a/testutil/testkeyring/gen_accounts/gen.go +++ b/testutil/testkeyring/gen_accounts/gen.go @@ -26,7 +26,7 @@ var ( ) func init() { - flag.StringVar(&flagOut, "out", defaultOutPath, "the path to the generated file.") + flag.StringVar(&flagOut, "out", defaultOutPath, "the path to the generated go source of pre-generated accounts.") flag.IntVar(&flagAccountsLimit, "limit", 100, "the number of accounts to generate.") } diff --git a/testutil/testkeyring/gen_accounts/template.go b/testutil/testkeyring/gen_accounts/template.go index 7d1ce91ec..e7dfb5b57 100644 --- a/testutil/testkeyring/gen_accounts/template.go +++ b/testutil/testkeyring/gen_accounts/template.go @@ -11,7 +11,7 @@ var ( `// DO NOT EDIT. This Code is generated by gen_accounts/gen.go, // changes will be overwritten upon regeneration. // -// To regenerate this file, use make go_testgen_accounts or go generate ./testutil/network/keyring.go. +// To regenerate this file, use make go_testgen_accounts or go generate ./testutil/testkeyring/keyring.go. package testkeyring diff --git a/testutil/testkeyring/keyring.go b/testutil/testkeyring/keyring.go index 73169aa1a..a441a986b 100644 --- a/testutil/testkeyring/keyring.go +++ b/testutil/testkeyring/keyring.go @@ -12,11 +12,15 @@ import ( "github.com/stretchr/testify/assert" ) +// CreatePreGeneratedKeyringAccounts uses the mnemonic from limit number of +// pre-generated accounts to populated the provided keyring, kr. func CreatePreGeneratedKeyringAccounts( t *testing.T, kr keyring.Keyring, limit int, ) []*PreGeneratedAccount { + t.Helper() + accounts := make([]*PreGeneratedAccount, limit) for i := range accounts { preGeneratedAccount := MustPreGeneratedAccountAtIndex(uint32(i)) From 114262870a1dc8872f4106b5b62d8919d7b22aa0 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 4 Dec 2023 12:50:11 +0100 Subject: [PATCH 23/33] wip --- testutil/testkeyring/gen_accounts/gen.go | 8 ++++---- testutil/testkeyring/keyring.go | 9 +++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/testutil/testkeyring/gen_accounts/gen.go b/testutil/testkeyring/gen_accounts/gen.go index 03709bb21..8b05da7d2 100644 --- a/testutil/testkeyring/gen_accounts/gen.go +++ b/testutil/testkeyring/gen_accounts/gen.go @@ -35,8 +35,8 @@ func main() { kr := keyring.NewInMemory(app.MakeEncodingConfig().Marshaler) - preGeneratedAccountsGobHexLines := make([]string, flagAccountsLimit) - for i := range preGeneratedAccountsGobHexLines { + preGeneratedAccountLines := make([]string, flagAccountsLimit) + for i := range preGeneratedAccountLines { record, mnemonic, err := kr.NewMnemonic( fmt.Sprintf("key-%d", i), keyring.English, @@ -59,10 +59,10 @@ func main() { log.Fatal(err) } - preGeneratedAccountsGobHexLines[i] = fmt.Sprintf(preGeneratedAccountLineFmt, preGeneratedAccountStr) + preGeneratedAccountLines[i] = fmt.Sprintf(preGeneratedAccountLineFmt, preGeneratedAccountStr) } - newPreGeneratedAccountIteratorArgLines := strings.Join(preGeneratedAccountsGobHexLines, "\n") + newPreGeneratedAccountIteratorArgLines := strings.Join(preGeneratedAccountLines, "\n") outputBuffer := new(bytes.Buffer) if err := accountsTableTemplate.Execute( outputBuffer, diff --git a/testutil/testkeyring/keyring.go b/testutil/testkeyring/keyring.go index a441a986b..f6c503d8e 100644 --- a/testutil/testkeyring/keyring.go +++ b/testutil/testkeyring/keyring.go @@ -13,7 +13,12 @@ import ( ) // CreatePreGeneratedKeyringAccounts uses the mnemonic from limit number of -// pre-generated accounts to populated the provided keyring, kr. +// pre-generated accounts to populated the provided keyring, kr. It then returns +// the pre-generated accounts which were used. +// +// TODO_CONSIDERATION: Returning a new PreGeneratedAccountIterator instead of +// the slice of accounts could be more idiomatic. It would only contain keys which +// are known to be in the keyring. func CreatePreGeneratedKeyringAccounts( t *testing.T, kr keyring.Keyring, @@ -38,5 +43,5 @@ func CreatePreGeneratedKeyringAccounts( accounts[i] = preGeneratedAccount } - return accounts + return accounts[:limit] } From aedfb6e95d47265a6988645dde72baaf93761894 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 4 Dec 2023 12:50:47 +0100 Subject: [PATCH 24/33] chore: chore: review feedback improvements Co-authored-by: Daniel Olshansky --- Makefile | 2 +- pkg/relayer/miner/gen/gen_fixtures.go | 2 +- pkg/relayer/miner/gen/template.go | 2 +- pkg/relayer/miner/miner_test.go | 2 +- pkg/relayer/miner/relay_fixtures_test.go | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index c7d1d1c25..6f8ed45ca 100644 --- a/Makefile +++ b/Makefile @@ -174,7 +174,7 @@ go_mockgen: ## Use `mockgen` to generate mocks used for testing purposes of all go generate ./pkg/crypto/rings/interface.go .PHONY: go_testgen_fixtures -go_fixturegen: ## Generate fixture data for unit tests +go_testgen_fixtures: ## Generate fixture data for unit tests go generate ./pkg/relayer/miner/miner_test.go .PHONY: go_testgen_accounts diff --git a/pkg/relayer/miner/gen/gen_fixtures.go b/pkg/relayer/miner/gen/gen_fixtures.go index 87e27bb01..59071d9ab 100644 --- a/pkg/relayer/miner/gen/gen_fixtures.go +++ b/pkg/relayer/miner/gen/gen_fixtures.go @@ -72,7 +72,7 @@ func init() { // random bytes. // Output file is truncated and overwritten if it already exists. // -// To regenerate all fixtures, use `make go_fixturegen`; to regenerate only this +// To regenerate all fixtures, use `make go_testgen_fixtures`; to regenerate only this // test's fixtures run `go generate ./pkg/relayer/miner/miner_test.go`. func main() { flag.Parse() diff --git a/pkg/relayer/miner/gen/template.go b/pkg/relayer/miner/gen/template.go index 8eb32c53b..c75e761a4 100644 --- a/pkg/relayer/miner/gen/template.go +++ b/pkg/relayer/miner/gen/template.go @@ -9,7 +9,7 @@ var ( `// DO NOT EDIT: this file was generated by gen/gen_fixtures.go, // changes made will be overwritten upon regeneration. // -// To regenerate all fixtures, use make go_fixturegen; to regenerate only this +// To regenerate all fixtures, use make go_testgen_fixture; to regenerate only this // test's fixtures run go generate ./pkg/relayer/miner/miner_test.go. package miner_test diff --git a/pkg/relayer/miner/miner_test.go b/pkg/relayer/miner/miner_test.go index c6958616d..9366f4121 100644 --- a/pkg/relayer/miner/miner_test.go +++ b/pkg/relayer/miner/miner_test.go @@ -27,7 +27,7 @@ const testDifficulty = 16 // it pipes pre-mined relay fixtures. It asserts that the observable only emits // mined relays with difficulty equal to or greater than testDifficulty. // -// To regenerate all fixtures, use `make go_fixturegen`; to regenerate only this +// To regenerate all fixtures, use `make go_testgen_fixtures`; to regenerate only this // test's fixtures run `go generate ./pkg/relayer/miner/miner_test.go`. func TestMiner_MinedRelays(t *testing.T) { var ( diff --git a/pkg/relayer/miner/relay_fixtures_test.go b/pkg/relayer/miner/relay_fixtures_test.go index 7a8042fde..c32dd4509 100644 --- a/pkg/relayer/miner/relay_fixtures_test.go +++ b/pkg/relayer/miner/relay_fixtures_test.go @@ -1,7 +1,7 @@ // DO NOT EDIT: this file was generated by gen/gen_fixtures.go, // changes made will be overwritten upon regeneration. // -// To regenerate all fixtures, use make go_fixturegen; to regenerate only this +// To regenerate all fixtures, use make go_testgen_fixture; to regenerate only this // test's fixtures run go generate ./pkg/relayer/miner/miner_test.go. package miner_test From 4e25816937780ca7b1e1bf6507454a126fd383e5 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 4 Dec 2023 12:54:19 +0100 Subject: [PATCH 25/33] fix: post-merge --- x/supplier/client/cli/helpers_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/x/supplier/client/cli/helpers_test.go b/x/supplier/client/cli/helpers_test.go index fd6ea06b4..5e3c27196 100644 --- a/x/supplier/client/cli/helpers_test.go +++ b/x/supplier/client/cli/helpers_test.go @@ -89,14 +89,16 @@ func networkWithClaimObjects( supplierAccts := make([]*testkeyring.PreGeneratedAccount, supplierCount) supplierAddrs := make([]string, supplierCount) for i := range supplierAccts { - account := preGeneratedAccts.MustNext() + account, ok := preGeneratedAccts.Next() + require.True(t, ok) supplierAccts[i] = account supplierAddrs[i] = account.Address.String() } appAccts := make([]*testkeyring.PreGeneratedAccount, appCount) appAddrs := make([]string, appCount) for i := range appAccts { - account := preGeneratedAccts.MustNext() + account, ok := preGeneratedAccts.Next() + require.True(t, ok) appAccts[i] = account appAddrs[i] = account.Address.String() } From 4508e1596b403289f959292bca3f27c6682dbe60 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 4 Dec 2023 12:56:16 +0100 Subject: [PATCH 26/33] chore: review feedback improvements Co-authored-by: Daniel Olshansky --- app/app.go | 1 + 1 file changed, 1 insertion(+) diff --git a/app/app.go b/app/app.go index dce2bca60..8dc0ace54 100644 --- a/app/app.go +++ b/app/app.go @@ -597,6 +597,7 @@ func New( ) applicationModule := applicationmodule.NewAppModule(appCodec, app.ApplicationKeeper, app.AccountKeeper, app.BankKeeper) + // TODO_TECHDEBT: Evaluate if this NB goes away after we upgrade to cosmos 0.5x // NB: there is a circular dependency between the supplier and session keepers. // Because the keepers are values (as opposed to pointers), they are copied // when passed into their respective module constructor functions. For this From a46d196028a2775c68b9e6d2b96318428748ed59 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 4 Dec 2023 13:02:59 +0100 Subject: [PATCH 27/33] chore: remove todo --- e2e/tests/init_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/e2e/tests/init_test.go b/e2e/tests/init_test.go index 5fa6fa3f2..a38c91e83 100644 --- a/e2e/tests/init_test.go +++ b/e2e/tests/init_test.go @@ -74,7 +74,6 @@ func (s *suite) Before() { s.buildAppMap() s.buildSupplierMap() - // TODO_IN_THIS_COMMIT: set up in before hooks flagSet := testclient.NewLocalnetFlagSet(s) clientCtx := testclient.NewLocalnetClientCtx(s, flagSet) s.supplierQueryClient = suppliertypes.NewQueryClient(clientCtx) From 2f5e5ff5e047198ce82eaf3e61e06d4d76ef8b78 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 4 Dec 2023 13:10:40 +0100 Subject: [PATCH 28/33] chore: self-review improvements --- e2e/tests/session.feature | 2 +- testutil/testclient/localnet.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/tests/session.feature b/e2e/tests/session.feature index cc03a5029..2a2d0f38d 100644 --- a/e2e/tests/session.feature +++ b/e2e/tests/session.feature @@ -5,5 +5,5 @@ Feature: Session Namespace When the supplier "supplier1" has serviced a session with "5" relays for service "svc1" for application "app1" And after the supplier creates a claim for the session for service "svc1" for application "app1" Then the claim created by supplier "supplier1" for service "svc1" for application "app1" should be persisted on-chain -# TODO_IN_THIS_COMMIT: ... +# TODO_IMPROVE: ... # And an event should be emitted... diff --git a/testutil/testclient/localnet.go b/testutil/testclient/localnet.go index d83969f21..6c60702eb 100644 --- a/testutil/testclient/localnet.go +++ b/testutil/testclient/localnet.go @@ -67,7 +67,7 @@ func NewLocalnetFlagSet(t gocuke.TestingT) *pflag.FlagSet { mockFlagSet := pflag.NewFlagSet("test", pflag.ContinueOnError) // TODO_IMPROVE: It would be nice if the value could be set correctly based // on whether the test using it is running in tilt or not. - mockFlagSet.String(flags.FlagNode, "tcp://sequencer-poktroll-sequencer:36657", "use localnet poktrolld node") + mockFlagSet.String(flags.FlagNode, CometLocalWebsocketURL, "use localnet poktrolld node") mockFlagSet.String(flags.FlagHome, "", "use localnet poktrolld node") mockFlagSet.String(flags.FlagKeyringBackend, "test", "use test keyring") err := mockFlagSet.Parse([]string{}) From 1ce457a03fe27274607ddbcb310ced072881fb1e Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 5 Dec 2023 11:02:56 +0100 Subject: [PATCH 29/33] chore: re Co-authored-by: Daniel Olshansky --- testutil/supplier/fixtures.go | 2 ++ x/supplier/client/cli/helpers_test.go | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/testutil/supplier/fixtures.go b/testutil/supplier/fixtures.go index b3b425240..bb1d858ea 100644 --- a/testutil/supplier/fixtures.go +++ b/testutil/supplier/fixtures.go @@ -75,6 +75,7 @@ func NewSessionFixturesWithPairings( return sessionFixturesByAppAddr } +// newSuppliers configures a supplier for the services provided and nil endpoints. func newSupplier(t *testing.T, addr string, services ...*sharedtypes.Service) *sharedtypes.Supplier { t.Helper() @@ -93,6 +94,7 @@ func newSupplier(t *testing.T, addr string, services ...*sharedtypes.Service) *s } } +// newApplication configures an application for the services provided. func newApplication(t *testing.T, addr string, services ...*sharedtypes.Service) *apptypes.Application { t.Helper() diff --git a/x/supplier/client/cli/helpers_test.go b/x/supplier/client/cli/helpers_test.go index 5e3c27196..2a9bd8116 100644 --- a/x/supplier/client/cli/helpers_test.go +++ b/x/supplier/client/cli/helpers_test.go @@ -159,6 +159,8 @@ func networkWithClaimObjects( return net, claims } +// encodeSessionHeader returns a base64 encoded string of a json +// serialized session header. func encodeSessionHeader( t *testing.T, appAddr string, @@ -179,6 +181,7 @@ func encodeSessionHeader( return base64.StdEncoding.EncodeToString(sessionHeaderBz) } +// createClaim sends a tx using the test CLI to create an on-chain claim func createClaim( t *testing.T, net *network.Network, @@ -211,6 +214,7 @@ func createClaim( require.NoError(t, err) require.Equal(t, float64(0), responseJson["code"], "code is not 0 in the response: %v", responseJson) + // TODO_TECHDEBT: Forward the actual claim in the response once the response is updated to return it. return &types.Claim{ SupplierAddress: supplierAddr, SessionId: sessionId, @@ -219,6 +223,9 @@ func createClaim( } } +// getSessionId sends a query using the test CLI to get a session for the inputs provided. +// It is assumed that the supplierAddr will be in that session based on the test design, but this +// is insured in this function before it's successfully returned. func getSessionId( t *testing.T, net *network.Network, From b49441c2b00000a9764f6bb04c5813850192f16b Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 5 Dec 2023 11:03:33 +0100 Subject: [PATCH 30/33] chore: review feedback improvements Co-authored-by: Daniel Olshansky --- e2e/tests/init_test.go | 2 ++ e2e/tests/session.feature | 1 + e2e/tests/session_steps_test.go | 2 +- pkg/client/tx/client.go | 3 ++- x/supplier/client/cli/helpers_test.go | 28 +++++++++----------- x/supplier/keeper/msg_server_create_claim.go | 6 +---- 6 files changed, 20 insertions(+), 22 deletions(-) diff --git a/e2e/tests/init_test.go b/e2e/tests/init_test.go index a38c91e83..81a12795d 100644 --- a/e2e/tests/init_test.go +++ b/e2e/tests/init_test.go @@ -60,6 +60,7 @@ func TestMain(m *testing.M) { type suite struct { gocuke.TestingT + // TODO_TECHDEBT: rename to `poktrolld`. pocketd *pocketdBin scenarioState map[string]any // temporary state for each scenario cdc codec.Codec @@ -85,6 +86,7 @@ func TestFeatures(t *testing.T) { gocuke.NewRunner(t, &suite{}).Path(flagFeaturesPath).Run() } +// TODO_TECHDEBT: rename `pocketd` to `poktrolld`. func (s *suite) TheUserHasThePocketdBinaryInstalled() { s.TheUserRunsTheCommand("help") } diff --git a/e2e/tests/session.feature b/e2e/tests/session.feature index 2a2d0f38d..3163eb471 100644 --- a/e2e/tests/session.feature +++ b/e2e/tests/session.feature @@ -7,3 +7,4 @@ Feature: Session Namespace Then the claim created by supplier "supplier1" for service "svc1" for application "app1" should be persisted on-chain # TODO_IMPROVE: ... # And an event should be emitted... +# TODO_INCOMPLETE: add step(s) for proof validation. diff --git a/e2e/tests/session_steps_test.go b/e2e/tests/session_steps_test.go index c097960c2..e2ee5b0ed 100644 --- a/e2e/tests/session_steps_test.go +++ b/e2e/tests/session_steps_test.go @@ -34,7 +34,7 @@ func (s *suite) AfterTheSupplierCreatesAClaimForTheSessionForServiceForApplicati var ctx, done = context.WithCancel(context.Background()) // TODO_CONSIDERATION: if this test suite gets more complex, it might make - // sense to refactor this key into a function that takes serviceId and appName + // sense to refactor this key into a function that takes serviceId and appName // as arguments and returns the key. eitherEventsBzReplayObs := s.scenarioState[eitherEventsBzReplayObsKey].(observable.ReplayObservable[either.Bytes]) diff --git a/pkg/client/tx/client.go b/pkg/client/tx/client.go index f31de9532..65b4792b7 100644 --- a/pkg/client/tx/client.go +++ b/pkg/client/tx/client.go @@ -89,7 +89,8 @@ type ( // the transactions subscription. type TxEvent struct { // Tx is the binary representation of the tx hash. - Tx []byte `json:"tx"` + Tx []byte `json:"tx"` + // TxResult is the CometBFT result of committing a transaction on-chain. Result TxResult `json:"result"` } diff --git a/x/supplier/client/cli/helpers_test.go b/x/supplier/client/cli/helpers_test.go index 2a9bd8116..9c8089868 100644 --- a/x/supplier/client/cli/helpers_test.go +++ b/x/supplier/client/cli/helpers_test.go @@ -13,19 +13,19 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" - types3 "github.com/cosmos/cosmos-sdk/codec/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/cosmos/cosmos-sdk/testutil/cli" - types4 "github.com/cosmos/cosmos-sdk/types" + testcli "github.com/cosmos/cosmos-sdk/testutil/cli" + sdktypes "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" "github.com/pokt-network/poktroll/cmd/pocketd/cmd" "github.com/pokt-network/poktroll/testutil/network" "github.com/pokt-network/poktroll/testutil/testkeyring" - types5 "github.com/pokt-network/poktroll/x/application/types" - types2 "github.com/pokt-network/poktroll/x/session/types" + apptypes "github.com/pokt-network/poktroll/x/application/types" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" - cli2 "github.com/pokt-network/poktroll/x/supplier/client/cli" + "github.com/pokt-network/poktroll/x/supplier/client/cli" "github.com/pokt-network/poktroll/x/supplier/types" ) @@ -65,8 +65,6 @@ func networkWithClaimObjects( sessionCount int, supplierCount int, appCount int, - // TODO_THIS_COMMIT: hook up to genesis state generation... - serviceCount int, ) (net *network.Network, claims []types.Claim) { t.Helper() @@ -113,7 +111,7 @@ func networkWithClaimObjects( // Add supplier and application module genesis states to the network config. cfg.GenesisState[types.ModuleName] = supplierGenesisBuffer - cfg.GenesisState[types5.ModuleName] = appGenesisBuffer + cfg.GenesisState[apptypes.ModuleName] = appGenesisBuffer // Construct the network with the configuration. net = network.New(t, cfg) @@ -169,14 +167,14 @@ func encodeSessionHeader( ) string { t.Helper() - argSessionHeader := &types2.SessionHeader{ + argSessionHeader := &sessiontypes.SessionHeader{ ApplicationAddress: appAddr, SessionStartBlockHeight: sessionStartHeight, SessionId: sessionId, SessionEndBlockHeight: sessionStartHeight + numBlocksPerSession, Service: &sharedtypes.Service{Id: testServiceId}, } - cdc := codec.NewProtoCodec(types3.NewInterfaceRegistry()) + cdc := codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) sessionHeaderBz := cdc.MustMarshalJSON(argSessionHeader) return base64.StdEncoding.EncodeToString(sessionHeaderBz) } @@ -204,10 +202,10 @@ func createClaim( fmt.Sprintf("--%s=%s", flags.FlagFrom, supplierAddr), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), - fmt.Sprintf("--%s=%s", flags.FlagFees, types4.NewCoins(types4.NewCoin(net.Config.BondDenom, math.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdktypes.NewCoins(sdktypes.NewCoin(net.Config.BondDenom, math.NewInt(10))).String()), } - responseRaw, err := cli.ExecTestCLICmd(ctx, cli2.CmdCreateClaim(), args) + responseRaw, err := testcli.ExecTestCLICmd(ctx, cli.CmdCreateClaim(), args) require.NoError(t, err) var responseJson map[string]interface{} err = json.Unmarshal(responseRaw.Bytes(), &responseJson) @@ -236,8 +234,8 @@ func getSessionId( t.Helper() ctx := context.TODO() - sessionQueryClient := types2.NewQueryClient(net.Validators[0].ClientCtx) - res, err := sessionQueryClient.GetSession(ctx, &types2.QueryGetSessionRequest{ + sessionQueryClient := sessiontypes.NewQueryClient(net.Validators[0].ClientCtx) + res, err := sessionQueryClient.GetSession(ctx, &sessiontypes.QueryGetSessionRequest{ ApplicationAddress: appAddr, Service: &sharedtypes.Service{Id: testServiceId}, BlockHeight: sessionStartHeight, diff --git a/x/supplier/keeper/msg_server_create_claim.go b/x/supplier/keeper/msg_server_create_claim.go index ce9a6e94a..7d911f95a 100644 --- a/x/supplier/keeper/msg_server_create_claim.go +++ b/x/supplier/keeper/msg_server_create_claim.go @@ -2,7 +2,6 @@ package keeper import ( "context" - "log" sdk "github.com/cosmos/cosmos-sdk/types" @@ -60,9 +59,6 @@ func (k msgServer) CreateClaim(goCtx context.Context, msg *suppliertypes.MsgCrea ) } - // TODO_TECHDEBT(#181): refactor once structured logging is available. - log.Printf("DEBUG: validated claim with sessionId %q for supplier %q", sessionRes.Session.SessionId, msg.GetSupplierAddress()) - logger. With( "session_id", sessionRes.GetSession().GetSessionId(), @@ -100,6 +96,6 @@ func (k msgServer) CreateClaim(goCtx context.Context, msg *suppliertypes.MsgCrea ). Debug("created claim") - // TODO_CONSIDERATION: perhaps it would be useful to return the claim in the response. + // TODO: return the claim in the response. return &suppliertypes.MsgCreateClaimResponse{}, nil } From a21ab57b7d3209e2851373cfa41b64b4a79c26b2 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 5 Dec 2023 11:58:15 +0100 Subject: [PATCH 31/33] chore: chore: review feedback improvements Co-authored-by: Daniel Olshansky --- e2e/tests/session_steps_test.go | 4 +-- pkg/client/tx/client.go | 16 ++++------ testutil/supplier/fixtures.go | 29 +++++++++---------- x/supplier/client/cli/query_claim_test.go | 3 -- .../keeper/msg_server_create_claim_test.go | 24 +++++++++------ 5 files changed, 36 insertions(+), 40 deletions(-) diff --git a/e2e/tests/session_steps_test.go b/e2e/tests/session_steps_test.go index e2ee5b0ed..2c016f706 100644 --- a/e2e/tests/session_steps_test.go +++ b/e2e/tests/session_steps_test.go @@ -10,10 +10,10 @@ import ( "strings" "time" + abci "github.com/cometbft/cometbft/abci/types" "github.com/stretchr/testify/require" eventsquery "github.com/pokt-network/poktroll/pkg/client/events_query" - "github.com/pokt-network/poktroll/pkg/client/tx" "github.com/pokt-network/poktroll/pkg/either" "github.com/pokt-network/poktroll/pkg/observable" "github.com/pokt-network/poktroll/pkg/observable/channel" @@ -50,7 +50,7 @@ func (s *suite) AfterTheSupplierCreatesAClaimForTheSessionForServiceForApplicati } // Unmarshal event data into a TxEventResponse object. - txEvent := &tx.TxEvent{} + txEvent := &abci.TxResult{} err = json.Unmarshal(eventBz, txEvent) require.NoError(s, err) diff --git a/pkg/client/tx/client.go b/pkg/client/tx/client.go index 65b4792b7..0317e39eb 100644 --- a/pkg/client/tx/client.go +++ b/pkg/client/tx/client.go @@ -9,8 +9,8 @@ import ( "fmt" "sync" + "cosmossdk.io/api/tendermint/abci" "cosmossdk.io/depinject" - abciTypes "github.com/cometbft/cometbft/abci/types" comettypes "github.com/cometbft/cometbft/types" cosmostypes "github.com/cosmos/cosmos-sdk/types" "go.uber.org/multierr" @@ -87,16 +87,10 @@ type ( // TxEvent is used to deserialize incoming websocket messages from // the transactions subscription. -type TxEvent struct { - // Tx is the binary representation of the tx hash. - Tx []byte `json:"tx"` - // TxResult is the CometBFT result of committing a transaction on-chain. - Result TxResult `json:"result"` -} - -type TxResult struct { - Events []abciTypes.Event `json:"events"` -} +// +// TODO_CONSIDERATION: either expose this via an interface and unexport this type, +// or remove it altogether. +type TxEvent = abci.TxResult // NewTxClient attempts to construct a new TxClient using the given dependencies // and options. diff --git a/testutil/supplier/fixtures.go b/testutil/supplier/fixtures.go index bb1d858ea..b13f1d74d 100644 --- a/testutil/supplier/fixtures.go +++ b/testutil/supplier/fixtures.go @@ -21,6 +21,12 @@ const ( // application address and the value is the session fixture. type SessionsByAppAddress map[string]sessiontypes.Session +// AppSupplierPair is a pairing of an application and a supplier address. +type AppSupplierPair struct { + AppAddr string + SupplierAddr string +} + // NewSessionFixturesWithPairings creates a map of session fixtures where the key // is the application address and the value is the session fixture. App/supplier // addresses are expected to be provided in alternating order (as pairs). The same @@ -29,34 +35,27 @@ type SessionsByAppAddress map[string]sessiontypes.Session func NewSessionFixturesWithPairings( t *testing.T, service *sharedtypes.Service, - appAndSupplierAddrPairs ...string, + appSupplierPairs ...AppSupplierPair, ) SessionsByAppAddress { t.Helper() - if len(appAndSupplierAddrPairs)%2 != 0 { - t.Fatalf("expected even number of app and supplier address pairs, got %d", len(appAndSupplierAddrPairs)) - } - // Initialize the session fixtures map. sessionFixturesByAppAddr := make(SessionsByAppAddress) // Iterate over the app and supplier address pairs (two indices at a time), // and create a session fixture for each app address. - for i := 0; i < len(appAndSupplierAddrPairs); i += 2 { - appAddr := appAndSupplierAddrPairs[i] - application := newApplication(t, appAddr, service) - - supplierAddr := appAndSupplierAddrPairs[i+1] - supplier := newSupplier(t, supplierAddr, service) + for _, appSupplierPair := range appSupplierPairs { + application := newApplication(t, appSupplierPair.AppAddr, service) + supplier := newSupplier(t, appSupplierPair.SupplierAddr, service) - if session, ok := sessionFixturesByAppAddr[appAddr]; ok { + if session, ok := sessionFixturesByAppAddr[appSupplierPair.AppAddr]; ok { session.Suppliers = append(session.Suppliers, supplier) continue } - sessionFixturesByAppAddr[appAddr] = sessiontypes.Session{ + sessionFixturesByAppAddr[appSupplierPair.AppAddr] = sessiontypes.Session{ Header: &sessiontypes.SessionHeader{ - ApplicationAddress: appAddr, + ApplicationAddress: appSupplierPair.AppAddr, Service: service, SessionStartBlockHeight: testBlockHeight, SessionId: testSessionId, @@ -67,7 +66,7 @@ func NewSessionFixturesWithPairings( NumBlocksPerSession: testBlocksPerSession, Application: application, Suppliers: []*sharedtypes.Supplier{ - newSupplier(t, supplierAddr, service), + newSupplier(t, appSupplierPair.SupplierAddr, service), }, } } diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index 6e5730e0d..ac18e94b7 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -20,13 +20,11 @@ func TestClaim_Show(t *testing.T) { sessionCount := 1 supplierCount := 3 appCount := 3 - serviceCount := 1 net, claims := networkWithClaimObjects( t, sessionCount, appCount, supplierCount, - serviceCount, ) ctx := net.Validators[0].ClientCtx @@ -106,7 +104,6 @@ func TestClaim_List(t *testing.T) { t, sessionCount, supplierCount, appCount, - serviceCount, ) ctx := net.Validators[0].ClientCtx diff --git a/x/supplier/keeper/msg_server_create_claim_test.go b/x/supplier/keeper/msg_server_create_claim_test.go index d0deaa0ad..30236b065 100644 --- a/x/supplier/keeper/msg_server_create_claim_test.go +++ b/x/supplier/keeper/msg_server_create_claim_test.go @@ -19,17 +19,20 @@ import ( const testServiceId = "svc1" func TestMsgServer_CreateClaim_Success(t *testing.T) { - appAddr, supplierAddr := sample.AccAddress(), sample.AccAddress() + appSupplierPair := supplier.AppSupplierPair{ + AppAddr: sample.AccAddress(), + SupplierAddr: sample.AccAddress(), + } service := &sharedtypes.Service{Id: testServiceId} - sessionFixturesByAddr := supplier.NewSessionFixturesWithPairings(t, service, appAddr, supplierAddr) + sessionFixturesByAddr := supplier.NewSessionFixturesWithPairings(t, service, appSupplierPair) supplierKeeper, sdkCtx := keepertest.SupplierKeeper(t, sessionFixturesByAddr) srv := keeper.NewMsgServerImpl(*supplierKeeper) ctx := sdk.WrapSDKContext(sdkCtx) claimMsg := newTestClaimMsg(t) - claimMsg.SupplierAddress = supplierAddr - claimMsg.SessionHeader.ApplicationAddress = appAddr + claimMsg.SupplierAddress = appSupplierPair.SupplierAddr + claimMsg.SessionHeader.ApplicationAddress = appSupplierPair.AppAddr createClaimRes, err := srv.CreateClaim(ctx, claimMsg) require.NoError(t, err) @@ -48,8 +51,11 @@ func TestMsgServer_CreateClaim_Success(t *testing.T) { func TestMsgServer_CreateClaim_Error(t *testing.T) { service := &sharedtypes.Service{Id: testServiceId} - appAddr, supplierAddr := sample.AccAddress(), sample.AccAddress() - sessionFixturesByAppAddr := supplier.NewSessionFixturesWithPairings(t, service, appAddr, supplierAddr) + appSupplierPair := supplier.AppSupplierPair{ + AppAddr: sample.AccAddress(), + SupplierAddr: sample.AccAddress(), + } + sessionFixturesByAppAddr := supplier.NewSessionFixturesWithPairings(t, service, appSupplierPair) supplierKeeper, sdkCtx := keepertest.SupplierKeeper(t, sessionFixturesByAppAddr) srv := keeper.NewMsgServerImpl(*supplierKeeper) @@ -64,8 +70,8 @@ func TestMsgServer_CreateClaim_Error(t *testing.T) { desc: "on-chain session ID must match claim msg session ID", claimMsgFn: func(t *testing.T) *types.MsgCreateClaim { msg := newTestClaimMsg(t) - msg.SupplierAddress = supplierAddr - msg.SessionHeader.ApplicationAddress = appAddr + msg.SupplierAddress = sample.AccAddress() + msg.SessionHeader.ApplicationAddress = sample.AccAddress() msg.SessionHeader.SessionId = "invalid_session_id" return msg @@ -76,7 +82,7 @@ func TestMsgServer_CreateClaim_Error(t *testing.T) { desc: "claim msg supplier address must be in the session", claimMsgFn: func(t *testing.T) *types.MsgCreateClaim { msg := newTestClaimMsg(t) - msg.SessionHeader.ApplicationAddress = appAddr + msg.SessionHeader.ApplicationAddress = sample.AccAddress() // Overwrite supplier address to one not included in the session fixtures. msg.SupplierAddress = sample.AccAddress() From b21f84379f9601c93d0485131250b19e625360aa Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 5 Dec 2023 12:25:46 +0100 Subject: [PATCH 32/33] fix: test --- x/supplier/keeper/msg_server_create_claim_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/supplier/keeper/msg_server_create_claim_test.go b/x/supplier/keeper/msg_server_create_claim_test.go index 30236b065..70ac48c79 100644 --- a/x/supplier/keeper/msg_server_create_claim_test.go +++ b/x/supplier/keeper/msg_server_create_claim_test.go @@ -70,8 +70,8 @@ func TestMsgServer_CreateClaim_Error(t *testing.T) { desc: "on-chain session ID must match claim msg session ID", claimMsgFn: func(t *testing.T) *types.MsgCreateClaim { msg := newTestClaimMsg(t) - msg.SupplierAddress = sample.AccAddress() - msg.SessionHeader.ApplicationAddress = sample.AccAddress() + msg.SupplierAddress = appSupplierPair.SupplierAddr + msg.SessionHeader.ApplicationAddress = appSupplierPair.AppAddr msg.SessionHeader.SessionId = "invalid_session_id" return msg @@ -82,7 +82,7 @@ func TestMsgServer_CreateClaim_Error(t *testing.T) { desc: "claim msg supplier address must be in the session", claimMsgFn: func(t *testing.T) *types.MsgCreateClaim { msg := newTestClaimMsg(t) - msg.SessionHeader.ApplicationAddress = sample.AccAddress() + msg.SessionHeader.ApplicationAddress = appSupplierPair.AppAddr // Overwrite supplier address to one not included in the session fixtures. msg.SupplierAddress = sample.AccAddress() From e58cd33b8a62fc0a20c0be54c1e829f4b876009d Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 6 Dec 2023 10:19:26 +0100 Subject: [PATCH 33/33] fix: disambiguate `CometLocalWebsocketURL` & `CometLocalTCPURL` (cherry picked from commit 358cb0ae8ffed76a75d83f42ef0a4ea94d185189) --- testutil/testclient/localnet.go | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/testutil/testclient/localnet.go b/testutil/testclient/localnet.go index 6c60702eb..c0374a7ba 100644 --- a/testutil/testclient/localnet.go +++ b/testutil/testclient/localnet.go @@ -12,11 +12,19 @@ import ( "github.com/pokt-network/poktroll/cmd/pocketd/cmd" ) -// CometLocalWebsocketURL provides a default URL pointing to the localnet websocket endpoint. -// -// TODO_IMPROVE: It would be nice if the value could be set correctly based -// on whether the test using it is running in tilt or not. -const CometLocalWebsocketURL = "ws://sequencer-poktroll-sequencer:36657/websocket" +const ( + // CometLocalTCPURL provides a default URL pointing to the localnet TCP endpoint. + // + // TODO_IMPROVE: It would be nice if the value could be set correctly based + // on whether the test using it is running in tilt or not. + CometLocalTCPURL = "tcp://sequencer-poktroll-sequencer:36657" + + // CometLocalWebsocketURL provides a default URL pointing to the localnet websocket endpoint. + // + // TODO_IMPROVE: It would be nice if the value could be set correctly based + // on whether the test using it is running in tilt or not. + CometLocalWebsocketURL = "ws://sequencer-poktroll-sequencer:36657/websocket" +) // EncodingConfig encapsulates encoding configurations for the Pocket application. var EncodingConfig = app.MakeEncodingConfig() @@ -67,7 +75,7 @@ func NewLocalnetFlagSet(t gocuke.TestingT) *pflag.FlagSet { mockFlagSet := pflag.NewFlagSet("test", pflag.ContinueOnError) // TODO_IMPROVE: It would be nice if the value could be set correctly based // on whether the test using it is running in tilt or not. - mockFlagSet.String(flags.FlagNode, CometLocalWebsocketURL, "use localnet poktrolld node") + mockFlagSet.String(flags.FlagNode, CometLocalTCPURL, "use localnet poktrolld node") mockFlagSet.String(flags.FlagHome, "", "use localnet poktrolld node") mockFlagSet.String(flags.FlagKeyringBackend, "test", "use test keyring") err := mockFlagSet.Parse([]string{})