From 4bcd8dec1d32ea2a2601599b7927c3b7354313b1 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 12 Dec 2023 12:50:31 +0100 Subject: [PATCH 01/58] refactor: `NewMinedRelay` to shared testutil --- pkg/relayer/session/session_test.go | 37 +----------------------- testutil/testrelayer/relays.go | 44 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 36 deletions(-) create mode 100644 testutil/testrelayer/relays.go diff --git a/pkg/relayer/session/session_test.go b/pkg/relayer/session/session_test.go index 09143d16e..cb1dddd82 100644 --- a/pkg/relayer/session/session_test.go +++ b/pkg/relayer/session/session_test.go @@ -12,14 +12,11 @@ import ( "github.com/pokt-network/poktroll/pkg/observable/channel" "github.com/pokt-network/poktroll/pkg/polylog/polyzero" "github.com/pokt-network/poktroll/pkg/relayer" - "github.com/pokt-network/poktroll/pkg/relayer/miner" "github.com/pokt-network/poktroll/pkg/relayer/session" "github.com/pokt-network/poktroll/testutil/testclient/testblock" "github.com/pokt-network/poktroll/testutil/testclient/testsupplier" "github.com/pokt-network/poktroll/testutil/testpolylog" "github.com/pokt-network/poktroll/testutil/testrelayer" - servicetypes "github.com/pokt-network/poktroll/x/service/types" - sessiontypes "github.com/pokt-network/poktroll/x/session/types" ) func TestRelayerSessionsManager_Start(t *testing.T) { @@ -54,7 +51,7 @@ func TestRelayerSessionsManager_Start(t *testing.T) { relayerSessionsManager.Start(ctx) // Publish a mined relay to the minedRelaysPublishCh to insert into the session tree. - minedRelay := newMinedRelay(t, sessionStartHeight, sessionEndHeight) + minedRelay := testrelayer.NewMinedRelay(t, sessionStartHeight, sessionEndHeight) minedRelaysPublishCh <- minedRelay // Wait a tick to allow the relayer sessions manager to process asynchronously. @@ -82,35 +79,3 @@ func TestRelayerSessionsManager_Start(t *testing.T) { // Wait a tick to allow the relayer sessions manager to process asynchronously. time.Sleep(250 * time.Millisecond) } - -// newMinedRelay returns a new mined relay with the given session start and end -// heights on the session header, and the bytes and hash fields populated. -func newMinedRelay( - t *testing.T, - sessionStartHeight int64, - sessionEndHeight int64, -) *relayer.MinedRelay { - relay := servicetypes.Relay{ - Req: &servicetypes.RelayRequest{ - Meta: &servicetypes.RelayRequestMetadata{ - SessionHeader: &sessiontypes.SessionHeader{ - SessionStartBlockHeight: sessionStartHeight, - SessionEndBlockHeight: sessionEndHeight, - }, - }, - }, - Res: &servicetypes.RelayResponse{}, - } - - // TODO_BLOCKER: use canonical codec to serialize the relay - relayBz, err := relay.Marshal() - require.NoError(t, err) - - relayHash := testrelayer.HashBytes(t, miner.DefaultRelayHasher, relayBz) - - return &relayer.MinedRelay{ - Relay: relay, - Bytes: relayBz, - Hash: relayHash, - } -} diff --git a/testutil/testrelayer/relays.go b/testutil/testrelayer/relays.go new file mode 100644 index 000000000..53ddbadc2 --- /dev/null +++ b/testutil/testrelayer/relays.go @@ -0,0 +1,44 @@ +package testrelayer + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/pokt-network/poktroll/pkg/relayer" + "github.com/pokt-network/poktroll/pkg/relayer/miner" + servicetypes "github.com/pokt-network/poktroll/x/service/types" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" +) + +// NewMinedRelay returns a new mined relay with the given session start and end +// heights on the session header, and the bytes and hash fields populated. +func NewMinedRelay( + t *testing.T, + sessionStartHeight int64, + sessionEndHeight int64, +) *relayer.MinedRelay { + relay := servicetypes.Relay{ + Req: &servicetypes.RelayRequest{ + Meta: &servicetypes.RelayRequestMetadata{ + SessionHeader: &sessiontypes.SessionHeader{ + SessionStartBlockHeight: sessionStartHeight, + SessionEndBlockHeight: sessionEndHeight, + }, + }, + }, + Res: &servicetypes.RelayResponse{}, + } + + // TODO_BLOCKER: use canonical codec to serialize the relay + relayBz, err := relay.Marshal() + require.NoError(t, err) + + relayHash := HashBytes(t, miner.DefaultRelayHasher, relayBz) + + return &relayer.MinedRelay{ + Relay: relay, + Bytes: relayBz, + Hash: relayHash, + } +} From 673911cc00d4b34b70aad7353ae4cffdc124b476 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 12 Dec 2023 12:30:32 +0100 Subject: [PATCH 02/58] refactor: claim & proof protobuf types --- proto/pocket/supplier/claim.proto | 8 ++-- proto/pocket/supplier/proof.proto | 12 +++--- proto/pocket/supplier/query.proto | 3 +- x/supplier/client/cli/helpers_test.go | 13 +++++-- x/supplier/client/cli/query_claim_test.go | 34 ++++++++--------- x/supplier/keeper/claim.go | 11 ++++-- x/supplier/keeper/claim_test.go | 20 ++++++---- x/supplier/keeper/msg_server_create_claim.go | 11 +++--- .../keeper/msg_server_create_claim_test.go | 8 ++-- x/supplier/keeper/proof.go | 6 +-- x/supplier/keeper/proof_test.go | 37 +++++++++++++------ x/supplier/keeper/query_claim_test.go | 12 +++--- x/supplier/keeper/query_proof_test.go | 4 +- 13 files changed, 105 insertions(+), 74 deletions(-) diff --git a/proto/pocket/supplier/claim.proto b/proto/pocket/supplier/claim.proto index 5b8121855..25b188040 100644 --- a/proto/pocket/supplier/claim.proto +++ b/proto/pocket/supplier/claim.proto @@ -4,11 +4,13 @@ package pocket.supplier; option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; import "cosmos_proto/cosmos.proto"; +import "pocket/session/session.proto"; // Claim is the serialized object stored on-chain for claims pending to be proven message Claim { string supplier_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // the address of the supplier that submitted this claim - string session_id = 2; // session id from the SessionHeader - uint64 session_end_block_height = 3; // session end block height from the SessionHeader - bytes root_hash = 4; // smt.SMST#Root() + // The session header of the session that this claim is for. + session.SessionHeader session_header = 2; + // Root hash returned from smt.SMST#Root(). + bytes root_hash = 3; } \ No newline at end of file diff --git a/proto/pocket/supplier/proof.proto b/proto/pocket/supplier/proof.proto index 26c1ab120..e3ed1f1b3 100644 --- a/proto/pocket/supplier/proof.proto +++ b/proto/pocket/supplier/proof.proto @@ -1,14 +1,14 @@ syntax = "proto3"; package pocket.supplier; +import "cosmos_proto/cosmos.proto"; +import "pocket/session/session.proto"; + option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; -// TODO_UPNEXT(@Olshansk): The structure below is the default (untouched) scaffolded type. Update -// and productionize it for our use case. message Proof { - string index = 1; - string supplier_address = 2; - string session_id = 3; - string merkle_proof = 4; + string supplier_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + session.SessionHeader session_header = 2; // the session header of the session that this claim is for + bytes merkle_proof = 3; // the serialized SMT proof } diff --git a/proto/pocket/supplier/query.proto b/proto/pocket/supplier/query.proto index b0d698d58..4980597bf 100644 --- a/proto/pocket/supplier/query.proto +++ b/proto/pocket/supplier/query.proto @@ -2,9 +2,10 @@ syntax = "proto3"; package pocket.supplier; +import "cosmos_proto/cosmos.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; -import "cosmos/base/query/v1beta1/pagination.proto"; import "pocket/supplier/params.proto"; import "pocket/shared/supplier.proto"; import "pocket/supplier/claim.proto"; diff --git a/x/supplier/client/cli/helpers_test.go b/x/supplier/client/cli/helpers_test.go index 9c8089868..e8a0753d0 100644 --- a/x/supplier/client/cli/helpers_test.go +++ b/x/supplier/client/cli/helpers_test.go @@ -214,10 +214,15 @@ func createClaim( // TODO_TECHDEBT: Forward the actual claim in the response once the response is updated to return it. return &types.Claim{ - SupplierAddress: supplierAddr, - SessionId: sessionId, - SessionEndBlockHeight: uint64(sessionEndHeight), - RootHash: rootHash, + SupplierAddress: supplierAddr, + SessionHeader: &sessiontypes.SessionHeader{ + ApplicationAddress: appAddress, + Service: &sharedtypes.Service{Id: testServiceId}, + SessionId: sessionId, + SessionStartBlockHeight: sessionStartHeight, + SessionEndBlockHeight: sessionEndHeight, + }, + RootHash: rootHash, } } diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index ac18e94b7..795b9a592 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -36,29 +36,29 @@ func TestClaim_Show(t *testing.T) { sessionId string supplierAddr string - args []string - err error - obj types.Claim + args []string + err error + claim types.Claim }{ { desc: "claim found", - sessionId: claims[0].SessionId, - supplierAddr: claims[0].SupplierAddress, + sessionId: claims[0].GetSessionHeader().GetSessionId(), + supplierAddr: claims[0].GetSupplierAddress(), - args: common, - obj: claims[0], + args: common, + claim: claims[0], }, { desc: "claim not found (wrong session ID)", sessionId: "wrong_session_id", - supplierAddr: claims[0].SupplierAddress, + supplierAddr: claims[0].GetSupplierAddress(), args: common, err: status.Error(codes.NotFound, "not found"), }, { desc: "claim not found (wrong supplier address)", - sessionId: claims[0].SessionId, + sessionId: claims[0].GetSessionHeader().GetSessionId(), supplierAddr: "wrong_supplier_address", args: common, @@ -82,10 +82,10 @@ func TestClaim_Show(t *testing.T) { var resp types.QueryGetClaimResponse require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) require.NotNil(t, resp.Claim) - require.Equal(t, - nullify.Fill(&tc.obj), - nullify.Fill(&resp.Claim), - ) + + require.Equal(t, tc.claim.GetSupplierAddress(), resp.Claim.GetSupplierAddress()) + require.Equal(t, tc.claim.GetRootHash(), resp.Claim.GetRootHash()) + require.Equal(t, tc.claim.GetSessionHeader(), resp.Claim.GetSessionHeader()) } }) } @@ -187,13 +187,13 @@ func TestClaim_List(t *testing.T) { }) t.Run("BySession", func(t *testing.T) { - sessionId := claims[0].SessionId + sessionId := claims[0].GetSessionHeader().SessionId args := prepareArgs(nil, 0, uint64(totalClaims), true) args = append(args, fmt.Sprintf("--%s=%s", cli.FlagSessionId, sessionId)) expectedClaims := make([]types.Claim, 0) for _, claim := range claims { - if claim.SessionId == sessionId { + if claim.GetSessionHeader().SessionId == sessionId { expectedClaims = append(expectedClaims, claim) } } @@ -212,13 +212,13 @@ func TestClaim_List(t *testing.T) { }) t.Run("ByHeight", func(t *testing.T) { - sessionEndHeight := claims[0].SessionEndBlockHeight + sessionEndHeight := claims[0].GetSessionHeader().GetSessionEndBlockHeight() args := prepareArgs(nil, 0, uint64(totalClaims), true) args = append(args, fmt.Sprintf("--%s=%d", cli.FlagSessionEndHeight, sessionEndHeight)) expectedClaims := make([]types.Claim, 0) for _, claim := range claims { - if claim.SessionEndBlockHeight == sessionEndHeight { + if claim.GetSessionHeader().GetSessionEndBlockHeight() == sessionEndHeight { expectedClaims = append(expectedClaims, claim) } } diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index 511d8f7da..ffa920bcc 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -18,7 +18,8 @@ func (k Keeper) InsertClaim(ctx sdk.Context, claim types.Claim) { // Update the primary store: ClaimPrimaryKey -> ClaimObject primaryStore := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) - primaryKey := types.ClaimPrimaryKey(claim.SessionId, claim.SupplierAddress) + sessionId := claim.GetSessionHeader().GetSessionId() + primaryKey := types.ClaimPrimaryKey(sessionId, claim.SupplierAddress) primaryStore.Set(primaryKey, claimBz) logger.Info("inserted claim for supplier %s with primaryKey %s", claim.SupplierAddress, primaryKey) @@ -32,10 +33,11 @@ func (k Keeper) InsertClaim(ctx sdk.Context, claim types.Claim) { // Update the session end height index: sessionEndHeight -> [ClaimPrimaryKey] sessionHeightStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimSessionEndHeightPrefix)) - heightKey := types.ClaimSupplierEndSessionHeightKey(claim.SessionEndBlockHeight, primaryKey) + sessionEndBlockHeight := uint64(claim.GetSessionHeader().GetSessionEndBlockHeight()) + heightKey := types.ClaimSupplierEndSessionHeightKey(sessionEndBlockHeight, primaryKey) sessionHeightStoreIndex.Set(heightKey, primaryKey) - logger.Info("indexed claim for supplier %s at session ending height %d", claim.SupplierAddress, claim.SessionEndBlockHeight) + logger.Info("indexed claim for supplier %s at session ending height %d", claim.SupplierAddress, sessionEndBlockHeight) } // RemoveClaim removes a claim from the store @@ -58,7 +60,8 @@ func (k Keeper) RemoveClaim(ctx sdk.Context, sessionId, supplierAddr string) { sessionHeightStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimSessionEndHeightPrefix)) addressKey := types.ClaimSupplierAddressKey(claim.SupplierAddress, primaryKey) - heightKey := types.ClaimSupplierEndSessionHeightKey(claim.SessionEndBlockHeight, primaryKey) + sessionEndBlockHeight := uint64(claim.GetSessionHeader().GetSessionEndBlockHeight()) + heightKey := types.ClaimSupplierEndSessionHeightKey(sessionEndBlockHeight, primaryKey) // Delete all the entries (primary store and secondary indices) primaryStore.Delete(primaryKey) diff --git a/x/supplier/keeper/claim_test.go b/x/supplier/keeper/claim_test.go index 4e38a43d0..41485ce79 100644 --- a/x/supplier/keeper/claim_test.go +++ b/x/supplier/keeper/claim_test.go @@ -11,6 +11,7 @@ import ( keepertest "github.com/pokt-network/poktroll/testutil/keeper" "github.com/pokt-network/poktroll/testutil/nullify" "github.com/pokt-network/poktroll/testutil/sample" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" "github.com/pokt-network/poktroll/x/supplier/keeper" "github.com/pokt-network/poktroll/x/supplier/types" ) @@ -22,8 +23,10 @@ func createNClaims(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Claim claims := make([]types.Claim, n) for i := range claims { claims[i].SupplierAddress = sample.AccAddress() - claims[i].SessionId = fmt.Sprintf("session-%d", i) - claims[i].SessionEndBlockHeight = uint64(i) + claims[i].SessionHeader = &sessiontypes.SessionHeader{ + SessionId: fmt.Sprintf("session-%d", i), + SessionEndBlockHeight: int64(i), + } claims[i].RootHash = []byte(fmt.Sprintf("rootHash-%d", i)) keeper.InsertClaim(ctx, claims[i]) } @@ -35,7 +38,7 @@ func TestClaim_Get(t *testing.T) { claims := createNClaims(keeper, ctx, 10) for _, claim := range claims { foundClaim, isClaimFound := keeper.GetClaim(ctx, - claim.SessionId, + claim.GetSessionHeader().GetSessionId(), claim.SupplierAddress, ) require.True(t, isClaimFound) @@ -49,12 +52,13 @@ func TestClaim_Remove(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t, nil) claims := createNClaims(keeper, ctx, 10) for _, claim := range claims { + sessionId := claim.GetSessionHeader().GetSessionId() keeper.RemoveClaim(ctx, - claim.SessionId, + sessionId, claim.SupplierAddress, ) _, isClaimFound := keeper.GetClaim(ctx, - claim.SessionId, + sessionId, claim.SupplierAddress, ) require.False(t, isClaimFound) @@ -90,7 +94,8 @@ func TestClaim_GetAll_ByHeight(t *testing.T) { claims := createNClaims(keeper, ctx, 10) // Get all claims for a given ending session block height - allFoundClaimsEndingAtHeight := keeper.GetClaimsByHeight(ctx, claims[6].SessionEndBlockHeight) + sessionEndHeight := claims[6].GetSessionHeader().GetSessionEndBlockHeight() + allFoundClaimsEndingAtHeight := keeper.GetClaimsByHeight(ctx, uint64(sessionEndHeight)) require.ElementsMatch(t, nullify.Fill([]types.Claim{claims[6]}), nullify.Fill(allFoundClaimsEndingAtHeight), @@ -102,7 +107,8 @@ func TestClaim_GetAll_BySession(t *testing.T) { claims := createNClaims(keeper, ctx, 10) // Get all claims for a given ending session block height - allFoundClaimsForSession := keeper.GetClaimsBySession(ctx, claims[8].SessionId) + sessionId := claims[8].GetSessionHeader().GetSessionId() + allFoundClaimsForSession := keeper.GetClaimsBySession(ctx, sessionId) require.ElementsMatch(t, nullify.Fill([]types.Claim{claims[8]}), nullify.Fill(allFoundClaimsForSession), diff --git a/x/supplier/keeper/msg_server_create_claim.go b/x/supplier/keeper/msg_server_create_claim.go index 7d911f95a..43814b7b0 100644 --- a/x/supplier/keeper/msg_server_create_claim.go +++ b/x/supplier/keeper/msg_server_create_claim.go @@ -81,17 +81,16 @@ func (k msgServer) CreateClaim(goCtx context.Context, msg *suppliertypes.MsgCrea // Construct and insert claim after all validation. claim := suppliertypes.Claim{ - SupplierAddress: msg.GetSupplierAddress(), - SessionId: msg.GetSessionHeader().GetSessionId(), - SessionEndBlockHeight: uint64(msg.GetSessionHeader().GetSessionEndBlockHeight()), - RootHash: msg.RootHash, + SupplierAddress: msg.GetSupplierAddress(), + SessionHeader: msg.GetSessionHeader(), + RootHash: msg.RootHash, } k.Keeper.InsertClaim(ctx, claim) logger. With( - "session_id", claim.GetSessionId(), - "session_end_height", claim.GetSessionEndBlockHeight(), + "session_id", claim.GetSessionHeader().GetSessionId(), + "session_end_height", claim.GetSessionHeader().GetSessionEndBlockHeight(), "supplier", claim.GetSupplierAddress(), ). Debug("created claim") diff --git a/x/supplier/keeper/msg_server_create_claim_test.go b/x/supplier/keeper/msg_server_create_claim_test.go index 70ac48c79..93bd2b5b2 100644 --- a/x/supplier/keeper/msg_server_create_claim_test.go +++ b/x/supplier/keeper/msg_server_create_claim_test.go @@ -43,10 +43,10 @@ func TestMsgServer_CreateClaim_Success(t *testing.T) { 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) + require.Equal(t, claimMsg.SessionHeader.SessionId, claims[0].GetSessionHeader().GetSessionId()) + require.Equal(t, claimMsg.SupplierAddress, claims[0].GetSupplierAddress()) + require.Equal(t, claimMsg.SessionHeader.GetSessionEndBlockHeight(), claims[0].GetSessionHeader().GetSessionEndBlockHeight()) + require.Equal(t, claimMsg.RootHash, claims[0].GetRootHash()) } func TestMsgServer_CreateClaim_Error(t *testing.T) { diff --git a/x/supplier/keeper/proof.go b/x/supplier/keeper/proof.go index bb9188a98..d70087fc5 100644 --- a/x/supplier/keeper/proof.go +++ b/x/supplier/keeper/proof.go @@ -12,20 +12,20 @@ func (k Keeper) SetProof(ctx sdk.Context, proof types.Proof) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ProofKeyPrefix)) b := k.cdc.MustMarshal(&proof) store.Set(types.ProofKey( - proof.Index, + proof.GetSessionHeader().GetSessionId(), ), b) } // GetProof returns a proof from its index func (k Keeper) GetProof( ctx sdk.Context, - index string, + sessionId string, ) (val types.Proof, found bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ProofKeyPrefix)) b := store.Get(types.ProofKey( - index, + sessionId, )) if b == nil { return val, false diff --git a/x/supplier/keeper/proof_test.go b/x/supplier/keeper/proof_test.go index a082a05bf..7a39c3828 100644 --- a/x/supplier/keeper/proof_test.go +++ b/x/supplier/keeper/proof_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "fmt" "strconv" "testing" @@ -9,6 +10,10 @@ import ( keepertest "github.com/pokt-network/poktroll/testutil/keeper" "github.com/pokt-network/poktroll/testutil/nullify" + "github.com/pokt-network/poktroll/testutil/sample" + sessionkeeper "github.com/pokt-network/poktroll/x/session/keeper" + 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" ) @@ -17,25 +22,35 @@ import ( var _ = strconv.IntSize func createNProofs(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Proof { - items := make([]types.Proof, n) - for i := range items { - items[i].Index = strconv.Itoa(i) + proofs := make([]types.Proof, n) + for i := range proofs { + proofs[i] = types.Proof{ + SupplierAddress: sample.AccAddress(), + SessionHeader: &sessiontypes.SessionHeader{ + ApplicationAddress: sample.AccAddress(), + Service: &sharedtypes.Service{Id: testServiceId}, + SessionId: fmt.Sprintf("session-%d", i), + SessionStartBlockHeight: 1, + SessionEndBlockHeight: 1 + sessionkeeper.NumBlocksPerSession, + }, + MerkleProof: nil, + } - keeper.SetProof(ctx, items[i]) + keeper.SetProof(ctx, proofs[i]) } - return items + return proofs } func TestProofGet(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t, nil) - items := createNProofs(keeper, ctx, 10) - for _, item := range items { + proofs := createNProofs(keeper, ctx, 10) + for _, proof := range proofs { rst, found := keeper.GetProof(ctx, - item.Index, + proof.GetSessionHeader().GetSessionId(), ) require.True(t, found) require.Equal(t, - nullify.Fill(&item), + nullify.Fill(&proof), nullify.Fill(&rst), ) } @@ -45,10 +60,10 @@ func TestProofRemove(t *testing.T) { items := createNProofs(keeper, ctx, 10) for _, item := range items { keeper.RemoveProof(ctx, - item.Index, + item.GetSessionHeader().GetSessionId(), ) _, found := keeper.GetProof(ctx, - item.Index, + item.GetSessionHeader().GetSessionId(), ) require.False(t, found) } diff --git a/x/supplier/keeper/query_claim_test.go b/x/supplier/keeper/query_claim_test.go index 1957362fa..1650c3bdf 100644 --- a/x/supplier/keeper/query_claim_test.go +++ b/x/supplier/keeper/query_claim_test.go @@ -31,7 +31,7 @@ func TestClaim_QuerySingle(t *testing.T) { desc: "First Claim", request: &types.QueryGetClaimRequest{ - SessionId: claims[0].SessionId, + SessionId: claims[0].GetSessionHeader().GetSessionId(), SupplierAddress: claims[0].SupplierAddress, }, @@ -42,7 +42,7 @@ func TestClaim_QuerySingle(t *testing.T) { desc: "Second Claim", request: &types.QueryGetClaimRequest{ - SessionId: claims[1].SessionId, + SessionId: claims[1].GetSessionHeader().GetSessionId(), SupplierAddress: claims[1].SupplierAddress, }, @@ -63,7 +63,7 @@ func TestClaim_QuerySingle(t *testing.T) { desc: "Claim Not Found - Random Supplier Address", request: &types.QueryGetClaimRequest{ - SessionId: claims[0].SessionId, + SessionId: claims[0].GetSessionHeader().GetSessionId(), SupplierAddress: sample.AccAddress(), }, @@ -81,7 +81,7 @@ func TestClaim_QuerySingle(t *testing.T) { { desc: "InvalidRequest - Missing SupplierAddress", request: &types.QueryGetClaimRequest{ - SessionId: claims[0].SessionId, + SessionId: claims[0].GetSessionHeader().GetSessionId(), // SupplierAddress: Intentionally Omitted, }, @@ -172,7 +172,7 @@ func TestClaim_QueryPaginated(t *testing.T) { t.Run("BySessionId", func(t *testing.T) { req := request(nil, 0, 0, true) req.Filter = &types.QueryAllClaimsRequest_SessionId{ - SessionId: claims[0].SessionId, + SessionId: claims[0].GetSessionHeader().GetSessionId(), } resp, err := keeper.AllClaims(wctx, req) require.NoError(t, err) @@ -182,7 +182,7 @@ func TestClaim_QueryPaginated(t *testing.T) { t.Run("BySessionEndHeight", func(t *testing.T) { req := request(nil, 0, 0, true) req.Filter = &types.QueryAllClaimsRequest_SessionEndHeight{ - SessionEndHeight: claims[0].SessionEndBlockHeight, + SessionEndHeight: uint64(claims[0].GetSessionHeader().GetSessionEndBlockHeight()), } resp, err := keeper.AllClaims(wctx, req) require.NoError(t, err) diff --git a/x/supplier/keeper/query_proof_test.go b/x/supplier/keeper/query_proof_test.go index a082d6e10..dcdec4c4e 100644 --- a/x/supplier/keeper/query_proof_test.go +++ b/x/supplier/keeper/query_proof_test.go @@ -31,14 +31,14 @@ func TestProofQuerySingle(t *testing.T) { { desc: "First", request: &types.QueryGetProofRequest{ - Index: msgs[0].Index, + Index: msgs[0].GetSessionHeader().GetSessionId(), }, response: &types.QueryGetProofResponse{Proof: msgs[0]}, }, { desc: "Second", request: &types.QueryGetProofRequest{ - Index: msgs[1].Index, + Index: msgs[1].GetSessionHeader().GetSessionId(), }, response: &types.QueryGetProofResponse{Proof: msgs[1]}, }, From fd558964df0844799b1124253fc5ee65aa4be384 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 7 Dec 2023 22:40:46 +0100 Subject: [PATCH 03/58] refactor: rename supplier keeper `UpsertClaim` & `UpsertProof` --- x/supplier/keeper/claim.go | 8 ++++---- x/supplier/keeper/claim_test.go | 2 +- x/supplier/keeper/msg_server_create_claim.go | 2 +- x/supplier/keeper/proof.go | 4 ++-- x/supplier/keeper/proof_test.go | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index ffa920bcc..09e3e635b 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -9,9 +9,9 @@ import ( "github.com/pokt-network/poktroll/x/supplier/types" ) -// InsertClaim adds a claim to the store -func (k Keeper) InsertClaim(ctx sdk.Context, claim types.Claim) { - logger := k.Logger(ctx).With("method", "InsertClaim") +// UpsertClaim inserts or updates a specific claim in the store by index. +func (k Keeper) UpsertClaim(ctx sdk.Context, claim types.Claim) { + logger := k.Logger(ctx).With("method", "UpsertClaim") claimBz := k.cdc.MustMarshal(&claim) parentStore := ctx.KVStore(k.storeKey) @@ -22,7 +22,7 @@ func (k Keeper) InsertClaim(ctx sdk.Context, claim types.Claim) { primaryKey := types.ClaimPrimaryKey(sessionId, claim.SupplierAddress) primaryStore.Set(primaryKey, claimBz) - logger.Info("inserted claim for supplier %s with primaryKey %s", claim.SupplierAddress, primaryKey) + logger.Info("upserted claim for supplier %s with primaryKey %s", claim.SupplierAddress, primaryKey) // Update the address index: supplierAddress -> [ClaimPrimaryKey] addressStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimSupplierAddressPrefix)) diff --git a/x/supplier/keeper/claim_test.go b/x/supplier/keeper/claim_test.go index 41485ce79..475350752 100644 --- a/x/supplier/keeper/claim_test.go +++ b/x/supplier/keeper/claim_test.go @@ -28,7 +28,7 @@ func createNClaims(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Claim SessionEndBlockHeight: int64(i), } claims[i].RootHash = []byte(fmt.Sprintf("rootHash-%d", i)) - keeper.InsertClaim(ctx, claims[i]) + keeper.UpsertClaim(ctx, claims[i]) } return claims } diff --git a/x/supplier/keeper/msg_server_create_claim.go b/x/supplier/keeper/msg_server_create_claim.go index 43814b7b0..74278d901 100644 --- a/x/supplier/keeper/msg_server_create_claim.go +++ b/x/supplier/keeper/msg_server_create_claim.go @@ -85,7 +85,7 @@ func (k msgServer) CreateClaim(goCtx context.Context, msg *suppliertypes.MsgCrea SessionHeader: msg.GetSessionHeader(), RootHash: msg.RootHash, } - k.Keeper.InsertClaim(ctx, claim) + k.Keeper.UpsertClaim(ctx, claim) logger. With( diff --git a/x/supplier/keeper/proof.go b/x/supplier/keeper/proof.go index d70087fc5..0dbff0855 100644 --- a/x/supplier/keeper/proof.go +++ b/x/supplier/keeper/proof.go @@ -7,8 +7,8 @@ import ( "github.com/pokt-network/poktroll/x/supplier/types" ) -// SetProof set a specific proof in the store from its index -func (k Keeper) SetProof(ctx sdk.Context, proof types.Proof) { +// UpsertProof inserts or updates a specific proof in the store by index. +func (k Keeper) UpsertProof(ctx sdk.Context, proof types.Proof) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ProofKeyPrefix)) b := k.cdc.MustMarshal(&proof) store.Set(types.ProofKey( diff --git a/x/supplier/keeper/proof_test.go b/x/supplier/keeper/proof_test.go index 7a39c3828..c03642e66 100644 --- a/x/supplier/keeper/proof_test.go +++ b/x/supplier/keeper/proof_test.go @@ -36,7 +36,7 @@ func createNProofs(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Proof MerkleProof: nil, } - keeper.SetProof(ctx, proofs[i]) + keeper.UpsertProof(ctx, proofs[i]) } return proofs } From 43cbf0e4e36b2d4517a89e17773303eb742a09ec Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 12 Dec 2023 17:04:45 +0100 Subject: [PATCH 04/58] refactor: misc. claim-side improvements --- proto/pocket/supplier/query.proto | 2 +- x/supplier/client/cli/query_claim.go | 6 +++--- .../{query_get_claim.go => query_validation.go} | 13 ++++++++++--- 3 files changed, 14 insertions(+), 7 deletions(-) rename x/supplier/types/{query_get_claim.go => query_validation.go} (85%) diff --git a/proto/pocket/supplier/query.proto b/proto/pocket/supplier/query.proto index 4980597bf..1af7fdb25 100644 --- a/proto/pocket/supplier/query.proto +++ b/proto/pocket/supplier/query.proto @@ -77,7 +77,7 @@ message QueryAllSupplierResponse { message QueryGetClaimRequest { string session_id = 1; - string supplier_address = 2; + string supplier_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; } message QueryGetClaimResponse { diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index 26a667a3b..d86d710ea 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -82,14 +82,14 @@ func CmdShowClaim() *cobra.Command { cmd := &cobra.Command{ Use: "show-claim ", Short: "shows a specific claim", - Long: `List a specific claim that the node being queried has access to (if it still exists) + Long: `List a specific claim that the node being queried has access to (if it still exists). -A unique claim can be defined via a session_id that a supplier participated in +A unique claim can be defined via a session_id that a given supplier participated in. Example: $ poktrolld --home=$(POKTROLLD_HOME) q claim show-claims --node $(POCKET_NODE)`, Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) (err error) { + RunE: func(cmd *cobra.Command, args []string) error { sessionId := args[0] supplierAddr := args[1] diff --git a/x/supplier/types/query_get_claim.go b/x/supplier/types/query_validation.go similarity index 85% rename from x/supplier/types/query_get_claim.go rename to x/supplier/types/query_validation.go index 0b7e1623f..0a7314232 100644 --- a/x/supplier/types/query_get_claim.go +++ b/x/supplier/types/query_validation.go @@ -1,10 +1,12 @@ package types import ( - fmt "fmt" + "context" sdkerrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/pokt-network/poktroll/pkg/polylog" ) // NOTE: Please note that these messages are not of type `sdk.Msg`, and are therefore not a message/request @@ -27,6 +29,9 @@ func (query *QueryGetClaimRequest) ValidateBasic() error { // ValidateBasic performs basic (non-state-dependant) validation on a QueryAllClaimsRequest. func (query *QueryAllClaimsRequest) ValidateBasic() error { + // TODO_TECHDEBT: update function signature to receive a context. + logger := polylog.Ctx(context.TODO()) + switch filter := query.Filter.(type) { case *QueryAllClaimsRequest_SupplierAddress: if _, err := sdk.AccAddressFromBech32(filter.SupplierAddress); err != nil { @@ -35,7 +40,9 @@ func (query *QueryAllClaimsRequest) ValidateBasic() error { case *QueryAllClaimsRequest_SessionId: // TODO_TECHDEBT: Validate the session ID once we have a deterministic way to generate it - fmt.Println("TODO: SessionID check is currently a noop: ", filter.SessionId) + logger.Warn(). + Str("session_id", filter.SessionId). + Msg("TODO: SessionID check is currently a noop") case *QueryAllClaimsRequest_SessionEndHeight: if filter.SessionEndHeight < 0 { @@ -44,7 +51,7 @@ func (query *QueryAllClaimsRequest) ValidateBasic() error { default: // No filter is set - fmt.Println("No specific filter set") + logger.Debug().Msg("No specific filter set") } return nil } From ef3cd99bac0b20dd68a0c35a6874a829df6e8eed Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 13 Dec 2023 21:54:12 +0100 Subject: [PATCH 05/58] chore: add TODOs --- x/supplier/keeper/proof.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/supplier/keeper/proof.go b/x/supplier/keeper/proof.go index 0dbff0855..aec052d5b 100644 --- a/x/supplier/keeper/proof.go +++ b/x/supplier/keeper/proof.go @@ -11,6 +11,7 @@ import ( func (k Keeper) UpsertProof(ctx sdk.Context, proof types.Proof) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ProofKeyPrefix)) b := k.cdc.MustMarshal(&proof) + // TODO_NEXT(@bryanchriswhite #141): Refactor keys to support multiple indices. store.Set(types.ProofKey( proof.GetSessionHeader().GetSessionId(), ), b) @@ -24,6 +25,7 @@ func (k Keeper) GetProof( ) (val types.Proof, found bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ProofKeyPrefix)) + // TODO_NEXT(@bryanchriswhite #141): Refactor proof keys to support multiple indices. b := store.Get(types.ProofKey( sessionId, )) @@ -38,10 +40,12 @@ func (k Keeper) GetProof( // RemoveProof removes a proof from the store func (k Keeper) RemoveProof( ctx sdk.Context, + // TODO_NEXT(@bryanchriswhite #141): Refactor proof keys to support multiple indices. index string, ) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ProofKeyPrefix)) + // TODO_NEXT(@bryanchriswhite #141): Refactor proof keys to support multiple indices. store.Delete(types.ProofKey( index, )) From f509fbf57ce7a0a22acab789cb9a34912093d25e Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 12 Dec 2023 12:32:21 +0100 Subject: [PATCH 06/58] refactor: supplier module keys --- x/supplier/keeper/claim.go | 4 ++-- x/supplier/types/key_claim.go | 37 ++++++++--------------------------- x/supplier/types/keys.go | 17 ++++++++++++++-- 3 files changed, 25 insertions(+), 33 deletions(-) diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index 09e3e635b..279b4c39c 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -33,7 +33,7 @@ func (k Keeper) UpsertClaim(ctx sdk.Context, claim types.Claim) { // Update the session end height index: sessionEndHeight -> [ClaimPrimaryKey] sessionHeightStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimSessionEndHeightPrefix)) - sessionEndBlockHeight := uint64(claim.GetSessionHeader().GetSessionEndBlockHeight()) + sessionEndBlockHeight := claim.GetSessionHeader().GetSessionEndBlockHeight() heightKey := types.ClaimSupplierEndSessionHeightKey(sessionEndBlockHeight, primaryKey) sessionHeightStoreIndex.Set(heightKey, primaryKey) @@ -60,7 +60,7 @@ func (k Keeper) RemoveClaim(ctx sdk.Context, sessionId, supplierAddr string) { sessionHeightStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimSessionEndHeightPrefix)) addressKey := types.ClaimSupplierAddressKey(claim.SupplierAddress, primaryKey) - sessionEndBlockHeight := uint64(claim.GetSessionHeader().GetSessionEndBlockHeight()) + sessionEndBlockHeight := claim.GetSessionHeader().GetSessionEndBlockHeight() heightKey := types.ClaimSupplierEndSessionHeightKey(sessionEndBlockHeight, primaryKey) // Delete all the entries (primary store and secondary indices) diff --git a/x/supplier/types/key_claim.go b/x/supplier/types/key_claim.go index 03186bf15..e570a2341 100644 --- a/x/supplier/types/key_claim.go +++ b/x/supplier/types/key_claim.go @@ -18,43 +18,22 @@ const ( ClaimSessionEndHeightPrefix = "Claim/height/" ) -// ClaimPrimaryKey returns the primary store key to retrieve a Claim by creating a composite key of the sessionId and supplierAddr +// ClaimPrimaryKey returns the primary store key used to retrieve a Claim by creating a composite key of the sessionId and supplierAddr. func ClaimPrimaryKey(sessionId, supplierAddr string) []byte { - var key []byte - // We are guaranteed uniqueness of the primary key if it's a composite of the (sessionId, supplierAddr) // because every supplier can only have one claim per session. - key = append(key, []byte(sessionId)...) - key = append(key, []byte("/")...) - key = append(key, []byte(supplierAddr)...) - key = append(key, []byte("/")...) - - return key + return KeyComposite([]byte(sessionId), []byte(supplierAddr)) } -// ClaimSupplierAddressKey returns the address key to iterate through claims given a supplier Address +// ClaimSupplierAddressKey returns the key used to iterate through claims given a supplier Address. func ClaimSupplierAddressKey(supplierAddr string, primaryKey []byte) []byte { - var key []byte - - key = append(key, []byte(supplierAddr)...) - key = append(key, []byte("/")...) - key = append(key, primaryKey...) - key = append(key, []byte("/")...) - - return key + return KeyComposite([]byte(supplierAddr), primaryKey) } -// ClaimSupplierAddressKey returns the address key to iterate through claims given a supplier Address -func ClaimSupplierEndSessionHeightKey(sessionEndHeight uint64, primaryKey []byte) []byte { - var key []byte - +// ClaimSupplierEndSessionHeightKey returns the key used to iterate through claims given a session end height. +func ClaimSupplierEndSessionHeightKey(sessionEndHeight int64, primaryKey []byte) []byte { heightBz := make([]byte, 8) - binary.BigEndian.PutUint64(heightBz, sessionEndHeight) - - key = append(key, []byte(heightBz)...) - key = append(key, []byte("/")...) - key = append(key, primaryKey...) - key = append(key, []byte("/")...) + binary.BigEndian.PutUint64(heightBz, uint64(sessionEndHeight)) - return key + return KeyComposite(heightBz, primaryKey) } diff --git a/x/supplier/types/keys.go b/x/supplier/types/keys.go index 21badb6a0..138fd0f19 100644 --- a/x/supplier/types/keys.go +++ b/x/supplier/types/keys.go @@ -1,5 +1,9 @@ package types +import ( + "bytes" +) + const ( // ModuleName defines the module name ModuleName = "supplier" @@ -14,6 +18,15 @@ const ( MemStoreKey = "mem_supplier" ) -func KeyPrefix(p string) []byte { - return []byte(p) +// KeyDelimiter is the delimiter for composite keys. +var KeyDelimiter = []byte("/") + +// KeyPrefix returns the given prefix as a byte slice for use with the KVStore. +func KeyPrefix(prefix string) []byte { + return []byte(prefix) +} + +// KeyComposite combines the given keys into a single key for use with KVStore. +func KeyComposite(keys ...[]byte) []byte { + return bytes.Join(keys, KeyDelimiter) } From 6817364a46918bdaa63daf79c80c2d1ef915326a Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 12 Dec 2023 17:04:59 +0100 Subject: [PATCH 07/58] refactor: supplier module errors --- x/supplier/client/cli/query_claim_test.go | 53 +++++++++++++--- x/supplier/keeper/query_claim.go | 10 +-- x/supplier/keeper/query_claim_test.go | 75 ++++++++++++++++++----- x/supplier/types/errors.go | 3 + x/supplier/types/query_validation.go | 9 ++- 5 files changed, 115 insertions(+), 35 deletions(-) diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index 795b9a592..598fa02bd 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -12,6 +12,7 @@ import ( "google.golang.org/grpc/status" "github.com/pokt-network/poktroll/testutil/nullify" + "github.com/pokt-network/poktroll/testutil/sample" "github.com/pokt-network/poktroll/x/supplier/client/cli" "github.com/pokt-network/poktroll/x/supplier/types" ) @@ -31,14 +32,16 @@ func TestClaim_Show(t *testing.T) { common := []string{ fmt.Sprintf("--%s=json", tmcli.OutputFlag), } + + var wrongSupplierAddr = sample.AccAddress() tests := []struct { desc string sessionId string supplierAddr string - args []string - err error - claim types.Claim + args []string + expectedErr error + claim types.Claim }{ { desc: "claim found", @@ -54,15 +57,47 @@ func TestClaim_Show(t *testing.T) { supplierAddr: claims[0].GetSupplierAddress(), args: common, - err: status.Error(codes.NotFound, "not found"), + + expectedErr: status.Error( + codes.NotFound, + types.ErrSupplierClaimNotFound.Wrapf( + // TODO_CONSIDERATION: factor out error message format strings to constants. + "session ID %q and supplier %q", + "wrong_session_id", + claims[0].GetSupplierAddress(), + ).Error(), + ), + }, + { + desc: "claim not found (invalid bech32 supplier address)", + sessionId: claims[0].GetSessionHeader().GetSessionId(), + supplierAddr: "invalid_bech32_supplier_address", + + args: common, + // NB: this is *NOT* a gRPC status error because the bech32 parse + // error occurs during request validation (i.e. client-side). + expectedErr: types.ErrSupplierInvalidAddress.Wrapf( + // TODO_CONSIDERATION: prefer using "%q" in error format strings + // to disambiguate empty string from space or no output. + "invalid supplier address for claim being retrieved %s; (decoding bech32 failed: invalid separator index -1)", + "invalid_bech32_supplier_address", + ), }, { desc: "claim not found (wrong supplier address)", sessionId: claims[0].GetSessionHeader().GetSessionId(), - supplierAddr: "wrong_supplier_address", + supplierAddr: wrongSupplierAddr, args: common, - err: status.Error(codes.NotFound, "not found"), + expectedErr: status.Error( + codes.NotFound, + types.ErrSupplierClaimNotFound.Wrapf( + // TODO_CONSIDERATION: factor out error message format strings to constants. + "session ID %q and supplier %q", + claims[0].GetSessionHeader().GetSessionId(), + wrongSupplierAddr, + ).Error(), + ), }, } for _, tc := range tests { @@ -73,10 +108,8 @@ func TestClaim_Show(t *testing.T) { } args = append(args, tc.args...) out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdShowClaim(), args) - if tc.err != nil { - stat, ok := status.FromError(tc.err) - require.True(t, ok) - require.ErrorIs(t, stat.Err(), tc.err) + if tc.expectedErr != nil { + require.ErrorContains(t, err, tc.expectedErr.Error()) } else { require.NoError(t, err) var resp types.QueryGetClaimResponse diff --git a/x/supplier/keeper/query_claim.go b/x/supplier/keeper/query_claim.go index 7009d3bab..29aee3634 100644 --- a/x/supplier/keeper/query_claim.go +++ b/x/supplier/keeper/query_claim.go @@ -3,7 +3,6 @@ package keeper import ( "context" "encoding/binary" - "fmt" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" @@ -80,11 +79,12 @@ func (k Keeper) AllClaims(goCtx context.Context, req *types.QueryAllClaimsReques func (k Keeper) Claim(goCtx context.Context, req *types.QueryGetClaimRequest) (*types.QueryGetClaimResponse, error) { if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") + err := types.ErrSupplierInvalidQueryRequest.Wrapf("request cannot be nil") + return nil, status.Error(codes.InvalidArgument, err.Error()) } if err := req.ValidateBasic(); err != nil { - return nil, err + return nil, status.Error(codes.InvalidArgument, err.Error()) } ctx := sdk.UnwrapSDKContext(goCtx) @@ -95,7 +95,9 @@ func (k Keeper) Claim(goCtx context.Context, req *types.QueryGetClaimRequest) (* req.SupplierAddress, ) if !found { - return nil, status.Error(codes.NotFound, fmt.Sprintf("claim not found for session %s and supplier %s", req.SessionId, req.SupplierAddress)) + err := types.ErrSupplierClaimNotFound.Wrapf("session ID %q and supplier %q", req.SessionId, req.SupplierAddress) + err = status.Error(codes.NotFound, err.Error()) + return nil, err } return &types.QueryGetClaimResponse{Claim: val}, nil diff --git a/x/supplier/keeper/query_claim_test.go b/x/supplier/keeper/query_claim_test.go index 1650c3bdf..714c23972 100644 --- a/x/supplier/keeper/query_claim_test.go +++ b/x/supplier/keeper/query_claim_test.go @@ -19,13 +19,15 @@ func TestClaim_QuerySingle(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t, nil) wctx := sdk.WrapSDKContext(ctx) claims := createNClaims(keeper, ctx, 2) + + var wrongSupplierAddr = sample.AccAddress() tests := []struct { desc string request *types.QueryGetClaimRequest - response *types.QueryGetClaimResponse - err error + response *types.QueryGetClaimResponse + expectedErr error }{ { desc: "First Claim", @@ -35,8 +37,8 @@ func TestClaim_QuerySingle(t *testing.T) { SupplierAddress: claims[0].SupplierAddress, }, - response: &types.QueryGetClaimResponse{Claim: claims[0]}, - err: nil, + response: &types.QueryGetClaimResponse{Claim: claims[0]}, + expectedErr: nil, }, { desc: "Second Claim", @@ -46,37 +48,58 @@ func TestClaim_QuerySingle(t *testing.T) { SupplierAddress: claims[1].SupplierAddress, }, - response: &types.QueryGetClaimResponse{Claim: claims[1]}, - err: nil, + response: &types.QueryGetClaimResponse{Claim: claims[1]}, + expectedErr: nil, }, { desc: "Claim Not Found - Random SessionId", request: &types.QueryGetClaimRequest{ SessionId: "not a real session id", - SupplierAddress: claims[0].SupplierAddress, + SupplierAddress: claims[0].GetSupplierAddress(), }, - err: status.Error(codes.NotFound, "claim not found"), + expectedErr: status.Error( + codes.NotFound, + types.ErrSupplierClaimNotFound.Wrapf( + // TODO_CONSIDERATION: factor out error message format strings to constants. + "session ID %q and supplier %q", + "not a real session id", + claims[0].GetSupplierAddress(), + ).Error(), + ), }, { - desc: "Claim Not Found - Random Supplier Address", + desc: "Claim Not Found - Wrong Supplier Address", request: &types.QueryGetClaimRequest{ SessionId: claims[0].GetSessionHeader().GetSessionId(), - SupplierAddress: sample.AccAddress(), + SupplierAddress: wrongSupplierAddr, }, - err: status.Error(codes.NotFound, "claim not found"), + expectedErr: status.Error( + codes.NotFound, + types.ErrSupplierClaimNotFound.Wrapf( + "session ID %q and supplier %q", + claims[0].GetSessionHeader().GetSessionId(), + wrongSupplierAddr, + ).Error(), + ), }, { desc: "InvalidRequest - Missing SessionId", request: &types.QueryGetClaimRequest{ // SessionId: Intentionally Omitted - SupplierAddress: claims[0].SupplierAddress, + SupplierAddress: claims[0].GetSupplierAddress(), }, - err: types.ErrSupplierInvalidSessionId, + expectedErr: status.Error( + codes.InvalidArgument, + types.ErrSupplierInvalidSessionId.Wrapf( + "invalid session ID for claim being retrieved %s", + "", + ).Error(), + ), }, { desc: "InvalidRequest - Missing SupplierAddress", @@ -85,14 +108,34 @@ func TestClaim_QuerySingle(t *testing.T) { // SupplierAddress: Intentionally Omitted, }, - err: types.ErrSupplierInvalidAddress, + expectedErr: status.Error( + codes.InvalidArgument, + types.ErrSupplierInvalidAddress.Wrap( + "invalid supplier address for claim being retrieved ; (empty address string is not allowed)", + ).Error(), + ), + }, + { + desc: "InvalidRequest - nil QueryGetClaimRequest", + request: nil, + + expectedErr: status.Error( + codes.InvalidArgument, + types.ErrSupplierInvalidQueryRequest.Wrap( + "request cannot be nil", + ).Error(), + ), }, } for _, tc := range tests { t.Run(tc.desc, func(t *testing.T) { response, err := keeper.Claim(wctx, tc.request) - if tc.err != nil { - require.ErrorContains(t, err, tc.err.Error()) + if tc.expectedErr != nil { + actualStatus, ok := status.FromError(err) + require.True(t, ok) + + require.ErrorIs(t, tc.expectedErr, actualStatus.Err()) + require.ErrorContains(t, err, tc.expectedErr.Error()) } else { require.NoError(t, err) require.Equal(t, diff --git a/x/supplier/types/errors.go b/x/supplier/types/errors.go index c175461ed..a1a4cb66a 100644 --- a/x/supplier/types/errors.go +++ b/x/supplier/types/errors.go @@ -18,4 +18,7 @@ var ( ErrSupplierInvalidService = sdkerrors.Register(ModuleName, 8, "invalid service in supplier") ErrSupplierInvalidClaimRootHash = sdkerrors.Register(ModuleName, 9, "invalid root hash") ErrSupplierInvalidSessionEndHeight = sdkerrors.Register(ModuleName, 10, "invalid session ending height") + ErrSupplierInvalidQueryRequest = sdkerrors.Register(ModuleName, 11, "invalid query request") + ErrSupplierClaimNotFound = sdkerrors.Register(ModuleName, 12, "claim not found") + ErrSupplierProofNotFound = sdkerrors.Register(ModuleName, 13, "proof not found") ) diff --git a/x/supplier/types/query_validation.go b/x/supplier/types/query_validation.go index 0a7314232..7ae243c8e 100644 --- a/x/supplier/types/query_validation.go +++ b/x/supplier/types/query_validation.go @@ -3,7 +3,6 @@ package types import ( "context" - sdkerrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/pokt-network/poktroll/pkg/polylog" @@ -17,12 +16,12 @@ import ( func (query *QueryGetClaimRequest) ValidateBasic() error { // Validate the supplier address if _, err := sdk.AccAddressFromBech32(query.SupplierAddress); err != nil { - return sdkerrors.Wrapf(ErrSupplierInvalidAddress, "invalid supplier address for claim being retrieved %s; (%v)", query.SupplierAddress, err) + return ErrSupplierInvalidAddress.Wrapf("invalid supplier address for claim being retrieved %s; (%v)", query.SupplierAddress, err) } // TODO_TECHDEBT: Validate the session ID once we have a deterministic way to generate it if query.SessionId == "" { - return sdkerrors.Wrapf(ErrSupplierInvalidSessionId, "invalid session ID for claim being retrieved %s", query.SessionId) + return ErrSupplierInvalidSessionId.Wrapf("invalid session ID for claim being retrieved %s", query.SessionId) } return nil } @@ -35,7 +34,7 @@ func (query *QueryAllClaimsRequest) ValidateBasic() error { switch filter := query.Filter.(type) { case *QueryAllClaimsRequest_SupplierAddress: if _, err := sdk.AccAddressFromBech32(filter.SupplierAddress); err != nil { - return sdkerrors.Wrapf(ErrSupplierInvalidAddress, "invalid supplier address for claims being retrieved %s; (%v)", filter.SupplierAddress, err) + return ErrSupplierInvalidAddress.Wrapf("invalid supplier address for claims being retrieved %s; (%v)", filter.SupplierAddress, err) } case *QueryAllClaimsRequest_SessionId: @@ -46,7 +45,7 @@ func (query *QueryAllClaimsRequest) ValidateBasic() error { case *QueryAllClaimsRequest_SessionEndHeight: if filter.SessionEndHeight < 0 { - return sdkerrors.Wrapf(ErrSupplierInvalidSessionEndHeight, "invalid session end height for claims being retrieved %d", filter.SessionEndHeight) + return ErrSupplierInvalidSessionEndHeight.Wrapf("invalid session end height for claims being retrieved %d", filter.SessionEndHeight) } default: From 6e6095274981203e6ff7a3ba797e260793fddcae Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 22 Dec 2023 14:36:02 +0100 Subject: [PATCH 08/58] chore: review feedback improvements Co-authored-by: harry <53987565+h5law@users.noreply.github.com> Co-authored-by: Daniel Olshansky --- x/supplier/client/cli/query_claim.go | 2 +- x/supplier/keeper/msg_server_create_claim.go | 2 +- x/supplier/types/query_validation.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index d86d710ea..31f5bcbb1 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -84,7 +84,7 @@ func CmdShowClaim() *cobra.Command { Short: "shows a specific claim", Long: `List a specific claim that the node being queried has access to (if it still exists). -A unique claim can be defined via a session_id that a given supplier participated in. +A unique claim can be defined via a session_id that the given supplier participated in. Example: $ poktrolld --home=$(POKTROLLD_HOME) q claim show-claims --node $(POCKET_NODE)`, diff --git a/x/supplier/keeper/msg_server_create_claim.go b/x/supplier/keeper/msg_server_create_claim.go index 74278d901..9181a526f 100644 --- a/x/supplier/keeper/msg_server_create_claim.go +++ b/x/supplier/keeper/msg_server_create_claim.go @@ -79,7 +79,7 @@ func (k msgServer) CreateClaim(goCtx context.Context, msg *suppliertypes.MsgCrea 2. [ ] msg distribution validation */ - // Construct and insert claim after all validation. + // Construct and upsert claim after all validation. claim := suppliertypes.Claim{ SupplierAddress: msg.GetSupplierAddress(), SessionHeader: msg.GetSessionHeader(), diff --git a/x/supplier/types/query_validation.go b/x/supplier/types/query_validation.go index 0a7314232..5264b6f79 100644 --- a/x/supplier/types/query_validation.go +++ b/x/supplier/types/query_validation.go @@ -42,7 +42,7 @@ func (query *QueryAllClaimsRequest) ValidateBasic() error { // TODO_TECHDEBT: Validate the session ID once we have a deterministic way to generate it logger.Warn(). Str("session_id", filter.SessionId). - Msg("TODO: SessionID check is currently a noop") + Msg("TODO: SessionID check in claim request validation is currently a noop") case *QueryAllClaimsRequest_SessionEndHeight: if filter.SessionEndHeight < 0 { @@ -51,7 +51,7 @@ func (query *QueryAllClaimsRequest) ValidateBasic() error { default: // No filter is set - logger.Debug().Msg("No specific filter set") + logger.Debug().Msg("No specific filter set when requesting claims") } return nil } From edc4e416e9a48b70176fba49375d2dbeab705c75 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 22 Dec 2023 14:37:38 +0100 Subject: [PATCH 09/58] chore: review feedback improvements Co-authored-by: Daniel Olshansky Co-authored-by: harry <53987565+h5law@users.noreply.github.com> --- proto/pocket/supplier/proof.proto | 6 ++++-- x/supplier/client/cli/query_claim.go | 2 ++ x/supplier/keeper/claim.go | 11 ++++++----- x/supplier/keeper/msg_server_stake_supplier.go | 15 ++++++++------- x/supplier/keeper/msg_server_unstake_supplier.go | 13 +++++++------ x/supplier/keeper/proof_test.go | 2 +- 6 files changed, 28 insertions(+), 21 deletions(-) diff --git a/proto/pocket/supplier/proof.proto b/proto/pocket/supplier/proof.proto index e3ed1f1b3..7ec927d05 100644 --- a/proto/pocket/supplier/proof.proto +++ b/proto/pocket/supplier/proof.proto @@ -8,7 +8,9 @@ option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; message Proof { string supplier_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - session.SessionHeader session_header = 2; // the session header of the session that this claim is for - bytes merkle_proof = 3; // the serialized SMT proof + // The session header of the session that this claim is for. + session.SessionHeader session_header = 2; + // The serialized SMST proof from the `#ClosestProof()` method. + bytes closest_merkle_proof = 3; } diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index 31f5bcbb1..b879f15c5 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -85,6 +85,8 @@ func CmdShowClaim() *cobra.Command { Long: `List a specific claim that the node being queried has access to (if it still exists). A unique claim can be defined via a session_id that the given supplier participated in. +Claims are pruned, according to protocol parameters, some time after their respective proof has been submitted and any dispute window has elapsed. +This is done to minimize the rate state accumulation by effectively eliminating claims as a long-term factor to persistence requirements. Example: $ poktrolld --home=$(POKTROLLD_HOME) q claim show-claims --node $(POCKET_NODE)`, diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index 09e3e635b..97ae8e3c6 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -2,6 +2,7 @@ package keeper import ( "encoding/binary" + "fmt" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" @@ -22,14 +23,14 @@ func (k Keeper) UpsertClaim(ctx sdk.Context, claim types.Claim) { primaryKey := types.ClaimPrimaryKey(sessionId, claim.SupplierAddress) primaryStore.Set(primaryKey, claimBz) - logger.Info("upserted claim for supplier %s with primaryKey %s", claim.SupplierAddress, primaryKey) + logger.Info(fmt.Sprintf("upserted claim for supplier %s with primaryKey %s", claim.SupplierAddress, primaryKey)) // Update the address index: supplierAddress -> [ClaimPrimaryKey] addressStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimSupplierAddressPrefix)) addressKey := types.ClaimSupplierAddressKey(claim.SupplierAddress, primaryKey) addressStoreIndex.Set(addressKey, primaryKey) - logger.Info("indexed claim for supplier %s with primaryKey %s", claim.SupplierAddress, primaryKey) + logger.Info(fmt.Sprintf("indexed claim for supplier %s with primaryKey %s", claim.SupplierAddress, primaryKey)) // Update the session end height index: sessionEndHeight -> [ClaimPrimaryKey] sessionHeightStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimSessionEndHeightPrefix)) @@ -37,7 +38,7 @@ func (k Keeper) UpsertClaim(ctx sdk.Context, claim types.Claim) { heightKey := types.ClaimSupplierEndSessionHeightKey(sessionEndBlockHeight, primaryKey) sessionHeightStoreIndex.Set(heightKey, primaryKey) - logger.Info("indexed claim for supplier %s at session ending height %d", claim.SupplierAddress, sessionEndBlockHeight) + logger.Info(fmt.Sprintf("indexed claim for supplier %s at session ending height %d", claim.SupplierAddress, sessionEndBlockHeight)) } // RemoveClaim removes a claim from the store @@ -51,7 +52,7 @@ func (k Keeper) RemoveClaim(ctx sdk.Context, sessionId, supplierAddr string) { primaryKey := types.ClaimPrimaryKey(sessionId, supplierAddr) claim, foundClaim := k.getClaimByPrimaryKey(ctx, primaryKey) if !foundClaim { - logger.Error("trying to delete non-existent claim with primary key %s for supplier %s and session %s", primaryKey, supplierAddr, sessionId) + logger.Error(fmt.Sprintf("trying to delete non-existent claim with primary key %s for supplier %s and session %s", primaryKey, supplierAddr, sessionId)) return } @@ -68,7 +69,7 @@ func (k Keeper) RemoveClaim(ctx sdk.Context, sessionId, supplierAddr string) { addressStoreIndex.Delete(addressKey) sessionHeightStoreIndex.Delete(heightKey) - logger.Info("deleted claim with primary key %s for supplier %s and session %s", primaryKey, supplierAddr, sessionId) + logger.Info(fmt.Sprintf("deleted claim with primary key %s for supplier %s and session %s", primaryKey, supplierAddr, sessionId)) } // GetClaim returns a Claim given a SessionId & SupplierAddr diff --git a/x/supplier/keeper/msg_server_stake_supplier.go b/x/supplier/keeper/msg_server_stake_supplier.go index 5fea47135..edd8ecee8 100644 --- a/x/supplier/keeper/msg_server_stake_supplier.go +++ b/x/supplier/keeper/msg_server_stake_supplier.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "fmt" sdkerrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" @@ -17,10 +18,10 @@ func (k msgServer) StakeSupplier( ctx := sdk.UnwrapSDKContext(goCtx) logger := k.Logger(ctx).With("method", "StakeSupplier") - logger.Info("About to stake supplier with msg: %v", msg) + logger.Info(fmt.Sprintf("About to stake supplier with msg: %v", msg)) if err := msg.ValidateBasic(); err != nil { - logger.Error("invalid MsgStakeSupplier: %v", msg) + logger.Error(fmt.Sprintf("invalid MsgStakeSupplier: %v", msg)) return nil, err } @@ -29,11 +30,11 @@ func (k msgServer) StakeSupplier( var coinsToDelegate sdk.Coin supplier, isSupplierFound := k.GetSupplier(ctx, msg.Address) if !isSupplierFound { - logger.Info("Supplier not found. Creating new supplier for address %s", msg.Address) + logger.Info(fmt.Sprintf("Supplier not found. Creating new supplier for address %s", msg.Address)) supplier = k.createSupplier(ctx, msg) coinsToDelegate = *msg.Stake } else { - logger.Info("Supplier found. Updating supplier for address %s", msg.Address) + logger.Info(fmt.Sprintf("Supplier found. Updating supplier for address %s", msg.Address)) currSupplierStake := *supplier.Stake if err = k.updateSupplier(ctx, &supplier, msg); err != nil { return nil, err @@ -44,7 +45,7 @@ func (k msgServer) StakeSupplier( // Retrieve the address of the supplier supplierAddress, err := sdk.AccAddressFromBech32(msg.Address) if err != nil { - logger.Error("could not parse address %s", msg.Address) + logger.Error(fmt.Sprintf("could not parse address %s", msg.Address)) return nil, err } @@ -52,13 +53,13 @@ func (k msgServer) StakeSupplier( // Send the coins from the supplier to the staked supplier pool err = k.bankKeeper.DelegateCoinsFromAccountToModule(ctx, supplierAddress, types.ModuleName, []sdk.Coin{coinsToDelegate}) if err != nil { - logger.Error("could not send %v coins from %s to %s module account due to %v", coinsToDelegate, supplierAddress, types.ModuleName, err) + logger.Error(fmt.Sprintf("could not send %v coins from %s to %s module account due to %v", coinsToDelegate, supplierAddress, types.ModuleName, err)) return nil, err } // Update the Supplier in the store k.SetSupplier(ctx, supplier) - logger.Info("Successfully updated supplier stake for supplier: %+v", supplier) + logger.Info(fmt.Sprintf("Successfully updated supplier stake for supplier: %+v", supplier)) return &types.MsgStakeSupplierResponse{}, nil } diff --git a/x/supplier/keeper/msg_server_unstake_supplier.go b/x/supplier/keeper/msg_server_unstake_supplier.go index 830a4c37a..79f86db3f 100644 --- a/x/supplier/keeper/msg_server_unstake_supplier.go +++ b/x/supplier/keeper/msg_server_unstake_supplier.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "fmt" sdk "github.com/cosmos/cosmos-sdk/types" @@ -16,7 +17,7 @@ func (k msgServer) UnstakeSupplier( ctx := sdk.UnwrapSDKContext(goCtx) logger := k.Logger(ctx).With("method", "UnstakeSupplier") - logger.Info("About to unstake supplier with msg: %v", msg) + logger.Info(fmt.Sprintf("About to unstake supplier with msg: %v", msg)) if err := msg.ValidateBasic(); err != nil { return nil, err @@ -25,27 +26,27 @@ func (k msgServer) UnstakeSupplier( // Check if the supplier already exists or not supplier, isSupplierFound := k.GetSupplier(ctx, msg.Address) if !isSupplierFound { - logger.Info("Supplier not found. Cannot unstake address %s", msg.Address) + logger.Info(fmt.Sprintf("Supplier not found. Cannot unstake address %s", msg.Address)) return nil, types.ErrSupplierNotFound } - logger.Info("Supplier found. Unstaking supplier for address %s", msg.Address) + logger.Info(fmt.Sprintf("Supplier found. Unstaking supplier for address %s", msg.Address)) // Retrieve the address of the supplier supplierAddress, err := sdk.AccAddressFromBech32(msg.Address) if err != nil { - logger.Error("could not parse address %s", msg.Address) + logger.Error(fmt.Sprintf("could not parse address %s", msg.Address)) return nil, err } // Send the coins from the supplier pool back to the supplier err = k.bankKeeper.UndelegateCoinsFromModuleToAccount(ctx, types.ModuleName, supplierAddress, []sdk.Coin{*supplier.Stake}) if err != nil { - logger.Error("could not send %v coins from %s module to %s account due to %v", supplier.Stake, supplierAddress, types.ModuleName, err) + logger.Error(fmt.Sprintf("could not send %v coins from %s module to %s account due to %v", supplier.Stake, supplierAddress, types.ModuleName, err)) return nil, err } // Update the Supplier in the store k.RemoveSupplier(ctx, supplierAddress.String()) - logger.Info("Successfully removed the supplier: %+v", supplier) + logger.Info(fmt.Sprintf("Successfully removed the supplier: %+v", supplier)) return &types.MsgUnstakeSupplierResponse{}, nil } diff --git a/x/supplier/keeper/proof_test.go b/x/supplier/keeper/proof_test.go index c03642e66..28d73ca7f 100644 --- a/x/supplier/keeper/proof_test.go +++ b/x/supplier/keeper/proof_test.go @@ -33,7 +33,7 @@ func createNProofs(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Proof SessionStartBlockHeight: 1, SessionEndBlockHeight: 1 + sessionkeeper.NumBlocksPerSession, }, - MerkleProof: nil, + ClosestMerkleProof: nil, } keeper.UpsertProof(ctx, proofs[i]) From dfb067d0b45735cdc46a98b49ec47c8a4042b74a Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 22 Dec 2023 14:51:02 +0100 Subject: [PATCH 10/58] chore: review feedback improvements Co-authored-by: Daniel Olshansky --- x/supplier/client/cli/query_claim_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index 598fa02bd..d7bd4aabd 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -61,7 +61,6 @@ func TestClaim_Show(t *testing.T) { expectedErr: status.Error( codes.NotFound, types.ErrSupplierClaimNotFound.Wrapf( - // TODO_CONSIDERATION: factor out error message format strings to constants. "session ID %q and supplier %q", "wrong_session_id", claims[0].GetSupplierAddress(), @@ -92,7 +91,6 @@ func TestClaim_Show(t *testing.T) { expectedErr: status.Error( codes.NotFound, types.ErrSupplierClaimNotFound.Wrapf( - // TODO_CONSIDERATION: factor out error message format strings to constants. "session ID %q and supplier %q", claims[0].GetSessionHeader().GetSessionId(), wrongSupplierAddr, From b82e49a33c82a09ba2001f0801ae562b24358cc9 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 19 Dec 2023 18:37:22 +0100 Subject: [PATCH 11/58] fix: pre-generated keyring accounts --- testutil/testkeyring/accounts_table.go | 202 ++++++++++++------------- 1 file changed, 101 insertions(+), 101 deletions(-) diff --git a/testutil/testkeyring/accounts_table.go b/testutil/testkeyring/accounts_table.go index 711a25018..f8d9d3bd9 100644 --- a/testutil/testkeyring/accounts_table.go +++ b/testutil/testkeyring/accounts_table.go @@ -1,111 +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_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 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"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF2N2VwZ3JzNmRjNjdrMHQweHZ2dHFleWVqaDlwbWpucHR1ZnFkZCIsIm1uZW1vbmljIjoiZGF1Z2h0ZXIgaHVtYmxlIG1vdXNlIHBlcnNvbiBodXNiYW5kIHdhc2ggZm9sZCBwbGFzdGljIG9ic2VydmUgbmF0aW9uIGZhdGhlciBwYXJ0eSBoZWFydCB3ZWVrZW5kIHllYXIgYWR1bHQgc3RyaWtlIGZsYW1lIGJhciBzaG9lIHZpYnJhbnQgaGFyYm9yIHJlcGVhdCBjYWJsZSJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFrODJtdThtZDNyOWc1M3BhNGxldGFnM2owZnoyMjlmemNxZGhodiIsIm1uZW1vbmljIjoic2VtaW5hciBpbnRvIHNuYWNrIGhhdCBzdGVlbCBzaWxseSBnbGFzcyBlbWJhcmsgd2Vla2VuZCBzbW9rZSBnaW5nZXIgd29sZiBzY3J1YiBnaXJsIG9seW1waWMgd2FzdGUgZXh0ZW5kIGx1Y2t5IHN0YXkgbWFyaW5lIGxlZnQgbGVhZGVyIGNvbWljIGltaXRhdGUifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFjcXZyM3Q3NGFhbncydzRjMzh3OWhwNzNwY2w4c2s2ejZlZmdkZSIsIm1uZW1vbmljIjoiYnVkZHkgc3BvcnQgYWdlbnQgbWVyZ2UgZGVwdGggcGVuIHNheSBmb2N1cyBkaW5vc2F1ciBjaXRpemVuIGFnYWluIG11Y2ggbWFuZGF0ZSBpZGVudGlmeSBkZWZ5IHJvYXN0IGxpYnJhcnkga2ljayBhbXVzZWQgdGhyb3cgc2xpY2Ugc2VlZCBkb2N0b3IgY29tZm9ydCJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFxZXJ0c2t2bmFuZTJmN215bWQ4cWY5aHpzbWU2bGx5cW16d3BrYSIsIm1uZW1vbmljIjoic2NhdHRlciBzdHVtYmxlIGJhc2Ugc2hpbmUgc2lsZW50IGNlcmVhbCBzaGFsbG93IHdhaXQgc21pbGUgZHV0eSB0b21vcnJvdyBwYXBlciB6b25lIG5hcnJvdyBkZWZlbnNlIGdlbnRsZSBiYXIgZW1wdHkgcG9ldCBzdGFtcCBkb21haW4gYnV0dGVyIHBldCBsYXVnaCJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFxZTJscTBkenN2YXV1OXlrdnh2NnhncGtraHVnNHd5cmRrMnh6OSIsIm1uZW1vbmljIjoiamFja2V0IGZsZWUgd2FyZmFyZSBhY2Nlc3Mgc3dpbmcgc2lkZSB0cmVhdCBleHBhbmQga2l0Y2hlbiBvZmZpY2UgcmFtcCBkaWNlIHBvc2l0aW9uIHdoaXNwZXIgbWluaW11bSBsaWNlbnNlIHN0aWNrIGF1dHVtbiBlbmVteSBzdXN0YWluIGJsdWUgaGFsZiBzd2FtcCB2ZWx2ZXQifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFycG44dnZhZjl6ZXYyc2owcHBlZnYzbGVxd3o0YWp3YWR1bGhyeiIsIm1uZW1vbmljIjoiZmF1bHQgcmF3IGNhc2ggcGF0cm9sIGJsdXIgbGVucyBtb3JhbCB3aGVlbCBiZXRyYXkgY2FsbCBrZWVwIHJlcXVpcmUgZmF2b3JpdGUgc2VtaW5hciBibGVzcyB1c2FnZSB3aGVyZSBzdXByZW1lIGZyZXNoIHBvZXQgc25hY2sgaGFsZiBzcGlrZSB0d28ifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF5ZWFjNXEzcHd0YXlmZnRqZGRjNmE0Y3R4N3R3bDB3Y3JweHE5NCIsIm1uZW1vbmljIjoiYWJhbmRvbiBraXRlIHByaWNlIGNhcnJ5IGFybSBmb2xkIHN5bWJvbCBzcGlkZXIgY29udmluY2Ugb3pvbmUgZnJvemVuIGNsb2cgdGFsayBteXRoIGVsZXBoYW50IG5lYXIgYmFzaWMgdHJ1bHkgZG9sbCBjYXR0bGUgZ2FsbGVyeSBidWJibGUgcm9vZiBzYWRuZXNzIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF6OGUybjR5cmRnZG42cjA3M2pzdWN5YTM4Y2c0ZjlxdGhkczA0MiIsIm1uZW1vbmljIjoiZWRnZSBsb3VuZ2UgbHVnZ2FnZSBwYXR0ZXJuIGRyYW1hIGludG8gdW5mb2xkIGFjaWQgZmFtaWx5IGJleW9uZCBuaWNlIGRyZWFtIGNsb3VkIGhhcnZlc3QgZmFybSBqb2luIGVtYm9keSBwYWN0IG93bmVyIHNob2Ugc2VsZWN0IGNlbnN1cyBzcHJheSBydWJiZXIifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE2ZW41d2Q0azQ3cTNndHBuZzRkYWN6c2FodGxzMDh3dWcweDdwOCIsIm1uZW1vbmljIjoidGVuYW50IGNhc3RsZSB0d2luIGFsc28gY2VtZW50IGRyYXN0aWMgbW90b3IgdmVyc2lvbiBtZWFuIGh1bWJsZSBwZXBwZXIgc3Rvb2wgaG9vZCByZWR1Y2UgaW5mbGljdCByZXF1aXJlIG9ibGlnZSByYW5nZSBib3ggc3BlbGwgYnJpc2sgYWRtaXQgc2xvdyB0dXJ0bGUifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEyOG5md2xqOTdzYWVsenhrdTR4Mmw4NWNxN3oybWNkZHY3Y2EyZCIsIm1uZW1vbmljIjoib3V0c2lkZSBtaW5kIHNpc3RlciBub3JtYWwgcHJvYmxlbSBzYWxvbiBzcGVsbCByZWNvcmQgaW5oZXJpdCBvYnZpb3VzIHN0YXRlIHNvbHV0aW9uIHNwZWVkIHVwc2V0IGJvaWwgY2FrZSB2aW50YWdlIHRyeSBzb3VyY2UgbGVnYWwgc291cCB0cmFnaWMgY29sb3IgdHlwaWNhbCJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF0NjZ1MmQ1endzemE3Mm5ycHl0ZGw5eDU2YXRhczI3eWVwZTllZyIsIm1uZW1vbmljIjoiZ29vZCBzaG9lIGhlYXJ0IGFpciBuYXJyb3cgY2xlYW4gdXJnZSB0aXNzdWUgZnJlcXVlbnQgdGVzdCB3cmlzdCBwb255IHNvY2NlciBwdWRkaW5nIGhvbmV5IGplbGx5IG1ldGhvZCBvcmRpbmFyeSByZWNlaXZlIGxvbmVseSBnbG9vbSBjaGVhcCB0cmF5IGxvZ2ljIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF6NnFlOTgyMmRzdnBncDRqbXcycG4zMjRzc2U2cmh3MDB3M3UzZyIsIm1uZW1vbmljIjoiYW1vdW50IGRlbWlzZSBnb3duIHNjaXNzb3JzIGNvbHVtbiBnaXZlIGh1cnJ5IGNyb3NzIGh1Z2UgY2xpbmljIHRyYXkgYmFzaWMgcGVuYWx0eSBkaW5uZXIgYnJpbmcgZWNvbm9teSBjYW5keSBhc3N1bWUgZGlzdGFuY2Ugb2ZmZXIgc2FkbmVzcyByaWdpZCB3aGVhdCB0aG91Z2h0In0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFwZGpsaDVtNWxxdHRoeDNucGd3anVnNnl4NzAyZjRneHFhc2RoMiIsIm1uZW1vbmljIjoiYWhlYWQgc2NhcmUgYXNrIHBhbG0gbWF0ZXJpYWwgZGVmaW5lIHNraSBleGhpYml0IGdsaW1wc2UgZ3Jhc3MgYnJhaW4gc2FkbmVzcyByZXNlbWJsZSBhdXR1bW4gZGVwYXJ0IHNsZWVwIHN0dW1ibGUgb2ZmZXIgY29uZHVjdCBmcmFtZSBpc2xhbmQgY2lyY2xlIHN0b3J5IGhhdmUifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF0eTUzanJ0YzN6NWN0cWdwd21wZmo2ZDVyNHZyZXA3d3J3NmFldiIsIm1uZW1vbmljIjoianVkZ2UgZnJhbWUgc2llZ2UgYWxjb2hvbCBvdXRwdXQgdW5pcXVlIGJvb3N0IGNvcm4gY2FnZSBvZG9yIGh1YiBhdWd1c3QgYXdha2UgbGF2YSBjb2FjaCBvYmplY3Qgc3VyZSBzdWdhciBwb25kIGNydWlzZSByYW5jaCBnb29zZSB3aGVuIGVtYm9keSJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFrdzNoZnJzcGo1dTVjMGdnOXUzMjAzcWttOHkyOHo1bnNmNDJuciIsIm1uZW1vbmljIjoiYXJyb3cgcG9saWNlIGFub3RoZXIgaWxsbmVzcyBvdmFsIGNlbGVyeSB0d2ljZSB0b3NzIHByb2Nlc3MgYXJyaXZlIGZlZSBzcHJheSBicm9uemUgcmFuZ2UgbGVtb24gZm9yZ2V0IGludG8gZ2VudGxlIGNsdW1wIGRlY2VtYmVyIHZlc3NlbCBtaW1pYyBub3JtYWwgaW5jbHVkZSJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF0bTZ2NjllNmpqbWVzY3Z2cDhqZ2s2OHo0MnhtczYzeXZ2cXY5diIsIm1uZW1vbmljIjoic3Ryb25nIHNpc3RlciB2ZWx2ZXQgdmVyc2lvbiBpbnNlY3Qgc3VmZmVyIHVuYXdhcmUgZWNvbG9neSBwbGFjZSBzY2F0dGVyIGFjaWQgb3JwaGFuIHNvbGlkIGRlY3JlYXNlIG5vaXNlIGdlbml1cyBvYnZpb3VzIHR1YmUgY2xhaW0gbWFnaWMgdGFsZW50IGJvc3MgaGludCBzaGVyaWZmIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE4MDRrcXZscjRhcHdsYXR6Mmw5bHR3MGx2Y2pyaHQ3ZWo5dHQyNiIsIm1uZW1vbmljIjoiaG9iYnkgdXNlZnVsIHJhdGUgdHViZSBvbWl0IHJhY2UgZ2xhc3MgcHJlZmVyIHNvZnQgdGVuIHByZXNlbnQgc291bCBsYXduIHJ1ZyBpbmR1c3RyeSBzYXRpc2Z5IGdyYXNzIGZvc3NpbCBhcm91bmQgY2F0IHJvYm90IG11c3QgY3J1ZWwgZXJhc2UifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFsa2NhOGo2OXBwbWpzbTVlOHJmamZrcTAzOGx0endtYWhydXUyZCIsIm1uZW1vbmljIjoiZGFyaW5nIGRpZXNlbCBibGVzcyBzY2lzc29ycyBwcm9maXQgZmVicnVhcnkgaWRsZSBvd24gZmFicmljIHBhcmVudCBkaXNoIHBvcHVsYXIgYmVoaW5kIG1lYWRvdyBsZWFmIHB1cnNlIG1pc2VyeSByaWIgc2VydmljZSBkZXB1dHkgd2FsbCBwaXN0b2wgYmlvbG9neSBub3cifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFua3NhdDZtcjY4dXBldHMyd21kNWdnMHdwdTU3cHZrcms4OW54bSIsIm1uZW1vbmljIjoidmV0ZXJhbiBndWlkZSBmYXRpZ3VlIHBpb25lZXIgaGludCB0YWNrbGUgc3B5IHRveSBhaGVhZCB0cnVseSBob21lIG5laXRoZXIgZGFtYWdlIGxlZ2VuZCBhZG1pdCBzbGFiIHN0dW1ibGUgZmFtaWx5IGluaGVyaXQgZmx1aWQgcGx1Y2sgbWFpZCB3aWxkIHRvaWxldCJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFyY3g5amV4MG5wNzNkbjV3emNsa2tta2Z6NGptbnhlNzhqeWxqOSIsIm1uZW1vbmljIjoicmVzcG9uc2UgYXVjdGlvbiBibHVzaCBzb21lb25lIGNyb3VjaCBkaWFtb25kIGZvY3VzIG1hdHJpeCBjYWJiYWdlIHRyaWFsIGJyaWdodCBjYWdlIHdyaXN0IHBlcmZlY3Qgc2llZ2Ugc3BhdGlhbCBzcG90IGNyaXNwIHdlYiBkcm9wIGV5ZSBkaWduaXR5IG9wZW4gcm9hZCJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFjcjJqOTYwaDQya2pzY3NjdDBqaGxwdzJxdGVzamMwenR6eTIybiIsIm1uZW1vbmljIjoiYXdmdWwgdHVpdGlvbiBjcm9zcyBlYWdsZSBuZWVkIHNpemUgc2l4IHJlY2FsbCBkaWFtb25kIHRhc2sgYnVkZ2V0IHNpZWdlIHNpZ24gY3JhbSBtYXJnaW4gd2FzdGUgZXhoaWJpdCBiYWNoZWxvciBjYXVzZSByb3NlIGRyYWZ0IHNwcmluZyBvbGQgdGlkZSJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFjczN3bWU1cHY4aGZ0N3RobWE5d3pjenRtZ3g3Z2d2dXo2c2R4bCIsIm1uZW1vbmljIjoiZGV2aWNlIGZyb3duIGx1Y2t5IHJ1bGUgcmViZWwgc2VyaWVzIGVtZXJnZSBtaWxsaW9uIHJvY2tldCB3b3JsZCBwcmljZSBjYW55b24gYWJzdHJhY3QgY2hhbXBpb24gY2hhbGsgd2V0IHJlbWVtYmVyIHByYWlzZSBnaXZlIG1vbml0b3IganVuayB0YXN0ZSBpbmRleCBzY2FuIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFlbjBucjYyZHN4bmxuMmZ3M3RwbGVmcWpmM2VhZG45aHBzdmQ4MyIsIm1uZW1vbmljIjoib3JjaGFyZCBlcnVwdCBhbGFybSBzaW1wbGUgZ2FzIHRyYW5zZmVyIHRyZWF0IHdvbGYgbGltaXQgZ3VuIGRyaXAgcmVtYWluIGp1aWNlIGVuZm9yY2UgcmFuZG9tIHZlbHZldCBwaXN0b2wgc3ViamVjdCBzdGlsbCBkaWV0IHJlc2N1ZSBzcGlkZXIgcG93ZXIgbXVzY2xlIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE3eXB0djZwcHd0a21nMDZnbnphNmp1cTZmYWRqNGhycncyMG5jcyIsIm1uZW1vbmljIjoic3VycHJpc2UgcGFycm90IHNsdXNoIGVuam95IHNvbHZlIHNldmVuIHNwYWNlIGJlY29tZSByZXRpcmUgaG9ybiBsZWdlbmQgcGlnZW9uIGNoYWxrIGdsb2JlIHJ1cmFsIGx1Y2t5IHNlYSBicm9vbSBjYW5hbCBidW5rZXIgZ3JvdyBhdWRpdCBzb2xpZCB3cmlzdCJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFjd3Zuc2w1ZDJ5empwZmQzbDR2OWtwbjdsaHE3ajNyOXA1eDV4eSIsIm1uZW1vbmljIjoiaHVtb3IgcmV2aWV3IHRlYW0gZGVwYXJ0IGNhbXAgc2ltaWxhciBjdXNoaW9uIHF1aXogaW5kaWNhdGUgZ2x1ZSB2aXNhIHBpbGwgZXJhIHN0YWdlIG1ham9yIHJvbWFuY2UgcXVpY2sgc3VyZSBkeW5hbWljIGNsYXcgaW5kb29yIHZhbGxleSB0cmFuc2ZlciBmaXRuZXNzIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFwaGY4YWwzdW5obXB2M2xmemFneXdlcXRmbHM4NHpoazI5MzdxOSIsIm1uZW1vbmljIjoiZW1icmFjZSB3ZWFyIHRydW1wZXQgZWZmb3J0IHBvbGFyIGFycmVzdCBodXNiYW5kIGdlc3R1cmUgZGlubmVyIGluZGV4IHRhYmxlIHByaWRlIHZlcnkgY3JvcCByb2JvdCBjYXJkIHNwaWNlIG1hdGNoIHNrYXRlIGFydHdvcmsgYmlrZSBtZW51IHRlbm5pcyB0aWx0In0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF2MjJrcjQ1OG5zZWd5ZDRoamswd3h2N3I4dHN2ZGR1eHgwczRsZSIsIm1uZW1vbmljIjoiZmF0aWd1ZSBndW4gZG9jdW1lbnQgYXJteSB0YXJnZXQgYmFjaGVsb3IgZ2xhcmUgYnVsayByZXNjdWUgZGllc2VsIGNyYWRsZSByb2FzdCB0b2RkbGVyIHByaXNvbiBiaWtlIGJyaWRnZSBhZGp1c3QgdHJpbSBvYnZpb3VzIGNvbGxlY3QgYmx1ZSBsaWJlcnR5IHNhdXNhZ2UgY2FnZSJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF2cG5tMnBwNWZrZXhwM2tmcW52OXA2bjAwN3Fjdng1NTdqYWVsZSIsIm1uZW1vbmljIjoid3JhcCBkcmluayBjaGFzZSBhbm5vdW5jZSByZWd1bGFyIG1vdGlvbiB0eXBpY2FsIHJhdyBjYXIgbmFpdmUgZ3Jhc3MgdHJpYWwgbGVnIGJ1ZGdldCBlbGJvdyBjYXRjaCBzZW5zZSBmb29kIHJlZ3VsYXIgY3VyaW91cyBiYXNpYyBjb250cm9sIHB1bHNlIGZyaWVuZCJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFmNGtlN214NWh5M2htbnE1OTNoZGpncGp6ejVsZzhnOHpwbDN2ciIsIm1uZW1vbmljIjoicmVzcG9uc2UgdG9wIG1pbGxpb24gd2luayB0ZWxsIHRhYmxlIHJlZmxlY3Qgc2thdGUgc3F1YXJlIG1lYWRvdyBwYXRjaCByZWNlaXZlIHNuYXAgYWlycG9ydCB0dW5uZWwgcmF2ZW4gZHJpZnQgZGlzY292ZXIgYXNzdW1lIGRvdmUgdGhlbiByYWRhciBlbGJvdyBzYW1lIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFhNnR3cnFyem1tajIzdGN6d3h0ZGZ3bGo3cGh6cmd0ZnE1d2swcSIsIm1uZW1vbmljIjoiZGFuY2Ugc291bmQgZmlzaCB5ZWFyIG1hc3RlciBkZXNwYWlyIGRlbnkgc3dlZXQgY2xhcmlmeSB2b2x1bWUgdGhyZWUgY2VyZWFsIHNwb29uIGdhZGdldCBkaXNvcmRlciBzbmFjayBzb2NrIHJlZ3VsYXIgZW1lcmdlIHRvb3RoIHZpc3VhbCB2aWJyYW50IHNldmVuIGxvdHRlcnkifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF5anIwOWZzYXVwdzY0MjU1Y3R0MDVoMjVzaGxhNHRweWU3cHhrNSIsIm1uZW1vbmljIjoiY3JhdGVyIG5hbWUgZnJhZ2lsZSBpc2xhbmQgc2tpbGwgY29hc3QgZW50cnkgc291bmQgcmFjZSBvbmNlIGNhcmdvIHN0YWJsZSB3aXNoIG1vb24gdW5jb3ZlciBhbHRlciBhY3Jvc3MgZGlnaXRhbCBkZW1hbmQgc3VpdCBmbG9vciBtZW50aW9uIHB1cGlsIG9seW1waWMifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEzcnpmdHF2d2t0d3E1bW11bXdqNjByNmF3dDVla2Rjc3Fya3V1cCIsIm1uZW1vbmljIjoic3BvbnNvciBsaW1pdCBpbmZsaWN0IGFjaWQgYWxhcm0gZnJlcXVlbnQgYmV0d2VlbiBob21lIHNpbWlsYXIgaW5jb21lIHBlcnNvbiBwYW5kYSBkaWNlIGxhYmVsIG1pc2VyeSBmdWVsIHJvY2tldCBwdWJsaWMga2lzcyB3aWxkIHNpY2sgY3J1Y2lhbCBtYWlsIG11c2ljIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFuZ3Rhbmw0OHN5dHhxNDNjeGpsc3E5cndraHV6bWVzZTc0cWx4ZyIsIm1uZW1vbmljIjoic3BhY2Ugb3Bwb3NlIG9wdGlvbiBibGVzcyBoYW1tZXIgc29sdXRpb24gZW5yaWNoIHZpbGxhZ2UgYmFycmVsIGtuZWUgZ3JhaW4gYXJlYSBzcGVsbCB0cmltIGJ1bGxldCBldmlsIGNvcmUgcmVzY3VlIGJpbmQgYXNwZWN0IG51dCBzaXplIHNwaGVyZSBwYWdlIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEwcnNlazgwbWM1dWVjZmZna3FxNm5xenM3OHNwZndyOHNsOHFwbiIsIm1uZW1vbmljIjoid2lzZG9tIGxlYXZlIGNlaWxpbmcgcmlmbGUgdmlicmFudCBzdGFuZCBwYXRjaCBvbHltcGljIHN3b3JkIHNjYWxlIG1hcmdpbiBzcGlrZSBtZWRhbCBnYXVnZSBicmllZiB2aWNpb3VzIGdvZGRlc3MgYWxtb3N0IGJsb29kIG9yZ2FuIGhhcnNoIGhlYWQgZm9sZCBwcmltYXJ5In0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF6dnF3N2NxZHA1ejQzeHlyOXh2c3pxanJoc3Z1ZjR2dmE4N2VuNiIsIm1uZW1vbmljIjoic3VubnkgZGVjYWRlIGZ1biBiZXN0IGZsZWUgY291Y2ggcHJlc2VudCByZWFkeSBhZ3JlZSBhcmVhIHVuYXdhcmUgcGFycm90IGhvY2tleSB3aGVyZSBzbHVzaCBwZXBwZXIgZmF1bHQgdGhyb3cgdmlzYSBsZW5kIGludG8gZXhoaWJpdCBhbW91bnQgY3J1c2gifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE2cm1nbmVjcjd3N3pldzY3dWtmaHk3eHBjbTk5bXJxbXA2c3NqbCIsIm1uZW1vbmljIjoibmVydmUgZG9vciBtb21lbnQgY2lnYXIgbmVlZCB1c2VmdWwgY29tYmluZSBhZ2UgcmlmbGUgcmV3YXJkIGZyb3plbiBsaXN0IHB1bmNoIHRlbm5pcyBob2xlIGNoYXJnZSBlaWdodCBwZW9wbGUgbGV0dGVyIGNoZWFwIGJ1dHRlciBpbmZvcm0gZmxhbWUgdGVuYW50In0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFybjVhOGdzejMycTl2OHhxMzB4NGc4dnV4dWxnOGNqMmx6dTZqZCIsIm1uZW1vbmljIjoiYXdhcmUgdHVydGxlIHN1biBjYW5ub24gZmFpbnQgaWNlIGhlYXJ0IHdpbGwgY2FrZSB2aWxsYWdlIGZhaW50IGhpcmUgdG93YXJkIHRlYWNoIHBvb2wgYWdlbnQgZ2luZ2VyIGlsbG5lc3MgdG9kYXkgZmV2ZXIgbWlyYWNsZSB3aGVyZSBkZXZlbG9wIHNlYXJjaCJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFqZ2Rja2g0azgyeXV4bjVwZXQyemx5NTV5eHVsN2ttbmx6Z25zcyIsIm1uZW1vbmljIjoiYm94IHRvcnRvaXNlIHNvdXRoIGZldyBkd2FyZiBjb3JhbCBtYWQgd2FsbnV0IHNvbGRpZXIgaHVtYW4gY2FyZ28gY3JhZGxlIGRpc2ggZ2FsYXh5IG5lcnZlIGF3a3dhcmQgZmFudGFzeSBpbm1hdGUga2FuZ2Fyb28gbWVzaCBmYW1lIGN1cnJlbnQgZ3JlYXQgY2FuYWwifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFkZzd2M2hkcDdhN2o5ZGZmZDh1NDBzZ2pmZmM1cXJ3OHU2bmsyYyIsIm1uZW1vbmljIjoiaW5oZXJpdCBwb25kIHB1YmxpYyBtaWxrIGJvZHkgY2hyb25pYyB0dXJ0bGUgZnVuIGRhZCBzdGFuZCBtb2RlbCBob2JieSByaWRnZSBjbHVtcCBtdXN0IGdhdGUgZm94IGxlYXJuIHNhdGlzZnkgc3BhdGlhbCB1cGdyYWRlIGNydWlzZSB3aXNkb20gc2hpcCJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFwNGE1NWU0dnowbHV0eDl0YWFtOTNoNHlmcTl2cjN5aDhwZWF2NiIsIm1uZW1vbmljIjoidHJlbmQgaW5zdGFsbCBtYXNrIGtpdCBydWxlIGtuZWUgdmFyaW91cyBzZXR0bGUgZ2F0aGVyIHNjaXNzb3JzIG9mZmVyIGF3ZnVsIG1haW4gYmlvbG9neSBwdXBpbCBkZXBhcnQgdG9uZ3VlIHdvcmsgYWN0b3IgcmVseSBhbmNpZW50IGRlZnkgYXJ0d29yayBqdWRnZSJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF6OWRsc3loenh2czNhYWFjNXU2a25nd2Y1cnVjcGg0anF2OHFraCIsIm1uZW1vbmljIjoib2JsaWdlIHBocmFzZSBpbmZvcm0gaGlzdG9yeSBlYXNpbHkgYmxvc3NvbSBjb3N0IHRvb3RoIGVhZ2xlIHRydWNrIHNtaWxlIGNydW1ibGUgbWF0cml4IHN3aW5nIG1hcnJpYWdlIG1lcnJ5IHNxdWlycmVsIHBvbGUgcmFjayBzb3VuZCBob3ZlciBoYW5kIHNhdG9zaGkgc3dpbmcifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEzcWw0ejlna2M1anJuYzg4YTlzcXVjejZ5cTJoaDg3aDM3bmc4MyIsIm1uZW1vbmljIjoicHJvcGVydHkgbXlzZWxmIHJlbW92ZSBicm9uemUgYnJhbmQgYW1hemluZyB3YXJtIGhhcmQgdHJpYmUgd2FybSBzY2hlbWUgd2VhciBkZWNsaW5lIHB1cGlsIHJhdGUgYXJ0ZWZhY3QgZHJvcCBlZGdlIGJhbGFuY2UgdG90YWwga2l3aSBxdW90ZSBjaXZpbCBmaWN0aW9uIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF3MGM3NWY1NHNlNnZkcHRhYzV4dHdjMjlqcmxmdHg3MDlrNGgyNSIsIm1uZW1vbmljIjoiY29pbCBzaXJlbiBkaXNvcmRlciB0ZW5hbnQgYWJzZW50IGp1ZGdlIHN1biBnYXJhZ2UgZXZpbCBtb3NxdWl0byBmYXRpZ3VlIGFtYXRldXIgbnVyc2Ugc2Npc3NvcnMgYm9hdCBjYXZlIGNhbnlvbiBwb3dlciB0aGVyZSBtYXJrZXQgc21vb3RoIHZhY2FudCBkZXZpY2UgYWN0In0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFkcmh3eTVscGhyN2c2cTd2Y3dhZ3lsYzc0Y2Fuc2M1dHd3ZDRrdiIsIm1uZW1vbmljIjoiZnJvemVuIGxpcXVpZCBhdm9pZCBmaW5nZXIgcGluayByZWdyZXQgc2hpbmUgbGV2ZWwgd2lkZSBzY2FyZSBtb3RoZXIgc21vb3RoIHNxdWFyZSBzdW5ueSB2aXJ1cyB0b3JjaCBiYW5hbmEgZm9yd2FyZCBpbXBvc2UgY2FuY2VsIGx1bmFyIG51cnNlIGFib3V0IGxheWVyIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE0MzA3eTk0NHBjMzg3NWhlNDU2M3NuejBoNGVmOTJyZzI2Y2syaiIsIm1uZW1vbmljIjoiY29yYWwgcmVqZWN0IGlzb2xhdGUgb3duIHN0b3J5IGJlZ2luIGNyZXcgYmx1ciB0ZW5uaXMgZGlldCBpbnRvIGNhYmxlIHJlcGFpciBleWUgYmV0d2VlbiBjbGltYiBqdWljZSBqYXp6IGdsYXJlIHNxdWVlemUgaGF2ZSB5b3V0aCBtZXNzYWdlIGFuZ3J5In0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF5bjdzM3Z5a3BxN3U5bmtmZGVxcjd4bWNjNDlya3lzOGRqdDJjdCIsIm1uZW1vbmljIjoiYm94IGZhaW50IHRvd24ga25vY2sgYnJpZ2h0IGFueSBhbnRpcXVlIHNsdXNoIGpvaW4gZ29hdCBzcGlyaXQgdHJlYXQgaG9sbG93IHNlY3Rpb24gZ3VpdGFyIHNjaG9vbCB2aXNpdCBzb2FwIG9zdHJpY2ggYmFsbCB0cmVhdCBjb2ZmZWUgZWxkZXIgb3BpbmlvbiJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE4eXQ5eWRlc3R1Nmd3eDJ2NDd6NGprc2ZzdHBjeTkyZGMyeTA2ayIsIm1uZW1vbmljIjoid2luayBmbGF2b3Igb3JiaXQgc2hvb3QgZG9scGhpbiBhZHVsdCBwaWVjZSBjcnVuY2ggYWN0b3IgaW5jaCBuZXJ2ZSByaXR1YWwgZ3JhaW4gYm9zcyB0d28gaG9yc2Ugcm9ja2V0IHdhbnQgcHV6emxlIHR3ZW50eSByZW5ldyBwcmlkZSBzcHJheSBjYWJiYWdlIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFza2cycXd4ZWx2eWFyZmtrZXpjZXh1bXBmcnVoMzRkemhuemdkciIsIm1uZW1vbmljIjoiZm9vZCBuYXN0eSBtYWNoaW5lIGRlcHV0eSBvcmNoYXJkIHJvdXRlIGhlbG1ldCBzdWl0IGVhZ2xlIHdvcmxkIGJyYXZlIGNyYW0gb3pvbmUgd29ybGQgZmFkZSBzaGVkIG1hZCBmb3JnZXQgdG9pbGV0IGFjY2VzcyBldm9rZSBjYXVnaHQgc3RlZWwga2lkbmV5In0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE0YzJrNXlodDB6MmdzdGo1ZWtxZDl4bXJmNXQ1enQ0djA4N25lMiIsIm1uZW1vbmljIjoiYXJvdW5kIHRydWx5IHN3YXAgZ2VuZXJhbCB3b3J0aCBzdWJtaXQgZXhjaGFuZ2UgZHJpdmUgY29tZSBkaW5vc2F1ciBzb3J0IGVsZWN0cmljIGRldGVjdCBwYXNzIHByb2plY3QgZ2lyYWZmZSBjb25maXJtIHNvbmcgc2hyaW1wIGxpYXIgZ3JhYiBhbGllbiByZXdhcmQgdG93biJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFweXd4NnBsbWhldHN0azZmeDZ2czJoaG55emY5dGtyYWh2bDR5aCIsIm1uZW1vbmljIjoiZWxzZSBzYWZlIHBlcHBlciBqb3kgbm9ibGUgaHVtYW4gY2xvY2sgcHJlZGljdCBwb3J0aW9uIHN1ZGRlbiBpbXBvc2UgdGlnZXIgY2FyYm9uIHllYXIgc2xpbSBncmFwZSBwcmV0dHkgZmFpdGggYnVyc3QgbWFzcyBjb3VwbGUgdGVzdCBtYXRoIGZlZWwifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEyeXJrbmNseTBzamo3NjM1NHgyYzllNWNsdGR2aG11bDBzbTAzZSIsIm1uZW1vbmljIjoicmVsYXggb3lzdGVyIGNhdGVnb3J5IGhlbiBhZGRyZXNzIGJveCBzaHJ1ZyBtYW5kYXRlIHdlYXRoZXIgc3BhY2Uga2luZCB0aGF0IGRpYXJ5IHBhZGRsZSBhdXR1bW4gZWRnZSBmYWl0aCB3cm9uZyBmaXggZ293biBzYXZlIG1hc3MgbGVnZW5kIGJ1bGsifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFoc2doejJnam5keWRwejIzc3g5eGxxa2tmZTNwM2xmOGp1NDZudiIsIm1uZW1vbmljIjoiZHVtYiBjYXRhbG9nIHBpc3RvbCBzb2xhciBzcG9vbiBodXJ0IHdhZ2UgYmVsb3cgcHJldmVudCB3aGVhdCBwcm9wZXJ0eSBzcG9uc29yIGNvbmNlcnQgc3lydXAgZ2lmdCByZXBsYWNlIGN1cmlvdXMgYXJyb3cgZmliZXIgYWJzZW50IGF3a3dhcmQgY291c2luIGFkdmljZSBleGNpdGUifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE4MHZqNTk1NDltdHc5aGw1eTZubDc1dTQzMzg3N3Z2OGRlNXFkdyIsIm1uZW1vbmljIjoid2ludGVyIHNwb2lsIG1hc2sgZ3JvdyB3YXZlIHBlcnNvbiB3YWdlIHJveWFsIGdvZGRlc3MgYWNjaWRlbnQgcHJvYmxlbSBjcmF3bCByZWplY3QgZ293biBlbm91Z2ggZmxvb3IgZ2xhbmNlIHJpb3QganVzdCB0b25ndWUgZmFpbnQgdmlydHVhbCBtb2RpZnkgZ2lmdCJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF6YzI1a2UzYXc3dXRlano3dDNqcXRkZHN2bWpza2d6OGpwdW5qdiIsIm1uZW1vbmljIjoiaG9ycm9yIGVhc3QgbWluZCBhY2hpZXZlIG1pZGRsZSBhbmFseXN0IHdyZXN0bGUgbWF4aW11bSBtb3RvciBvc3RyaWNoIHRvZSByb29tIGNsaXAgZXh0cmEgcHJldmVudCBhdWRpdCBjb3VzaW4gY2Fub2UgZGlubmVyIGNoYXQgYWJzZW50IHZlbnVlIHRocml2ZSBuaWdodCJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFheXFtandkM2xhOGE2cTY2NG43YW5ucTdnNDhubTV3Y3J0dnNxMCIsIm1uZW1vbmljIjoidG9wIHNlY3JldCB5b3V0aCBncml0IHN0cm9uZyByYW5jaCBqYXIgZGVsaXZlciBzdHJlZXQgZGVjaWRlIGNvdXBsZSBjcml0aWMgbWl4ZWQgYWxsIHJpb3Qgc2VlZCByZWdpb24gZXRlcm5hbCBhbmNpZW50IGFscGhhIGFtb25nIGh1bnQgbWl4ZWQgYWN0In0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFxcjB3bXdtOHRxN2g2ZHdlcjRoazV1NWU5bnVzeTBtZWFuemUzeSIsIm1uZW1vbmljIjoibWFuc2lvbiBkaWVzZWwgZGlub3NhdXIgbHV4dXJ5IHN1Y2ggb2JzY3VyZSBlbmVyZ3kgcm9va2llIHJpcHBsZSBkZW50aXN0IGF3YXJlIHByZXNlbnQgb3duZXIgY2FjdHVzIGdyYWIgZ2FyZGVuIHByb21vdGUgZ3VpbHQgaHVuZ3J5IHRyYWRlIHN1Z2dlc3QgdmlhYmxlIG5vdmVsIHVuaXZlcnNlIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFqcGE5OTdwZ3EzajBza3V2cHQ0M3VkdXlwNXZod2NwM2ZleTAydCIsIm1uZW1vbmljIjoibW92ZSBzd2FwIG92ZW4gdG9wIG1vbnRoIGV4cGlyZSBob25leSBzdWJtaXQga25pZmUgYXZvY2FkbyB3b29kIG5ldHdvcmsgbWFwbGUgYmx1ciB2b2ljZSBzdWNoIGJyYW5kIGNvY29udXQgYmFubmVyIGVhcm4gbGVvcGFyZCB0dW1ibGUgaG90ZWwgc3Bpcml0In0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF4NWZzajJsbHJ3a2Y4NXFsanBrZTY1eDAybGU1dWp0cWt0M25tNiIsIm1uZW1vbmljIjoiZmV0Y2ggc3RhaXJzIGF2b2NhZG8gbWVtYmVyIHN0dWZmIGFoZWFkIHR1bWJsZSBkaXNtaXNzIHNocnVnIHdhZ29uIGdyYWluIGp1ZGdlIGxlbmd0aCBsb2FkIGN1cnJlbnQgcmFiYml0IG9wZW4gcHJvYmxlbSBlbmZvcmNlIGNvcHkgcGllY2Ugc29sYXIgZXh0cmEgc2tpcnQifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF5ZzgyeTJnd3N2MGM5a201OXFtNjN2bjJ3NGxkcmQ3OXZnN2xjZyIsIm1uZW1vbmljIjoiaWNlIGhpbnQgaG9ybiBsYWJlbCB0aHVuZGVyIHN3YXJtIGNlbGVyeSBzY3JpcHQgZXhlY3V0ZSB2aXRhbCBmZW1hbGUgZ2luZ2VyIGNvcHBlciBmYXRpZ3VlIGxheWVyIGluc3BpcmUgc2lsbHkgZ3Jhdml0eSBtYXRjaCBpdm9yeSBkZXNpZ24gZGFzaCBleGNoYW5nZSBoaXN0b3J5In0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF6ajB3cmcyc2Z6Zzllamp5aHI3emp6bG11em55am1sNmQzZDN3eCIsIm1uZW1vbmljIjoic2NydWIgY291cGxlIGRhbXAgaG9tZSBwYWlyIGNpcmNsZSBiZWF1dHkgZmxvb3Igcm9hZCBzaHkgdHJhZmZpYyBkaWNlIGdyYWluIHRvbW9ycm93IHBlbiBtZWFzdXJlIGxpZmUgY2FycnkgbWlsayBsaXZlIGd1aWx0IHB1c2ggbG9jYWwgY2F0dGxlIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFmYW1uc3hqenZ0Z3VkZmU2cXQ1eHlzc2gzcGY1cjd5cGZodmY5dyIsIm1uZW1vbmljIjoiY2Fubm9uIGJlbmNoIG1vdXNlIHNjYXR0ZXIgZmF0IGhvY2tleSBraXdpIGFzc2F1bHQgZGVjYWRlIG9jY3VyIHJlc291cmNlIHRvZSBhYmlsaXR5IGJlZWYgYmVuY2ggZGFkIHNoaXZlciBlbXBsb3kgdGVhY2ggcmVtYWluIHdlYXBvbiByYXJlIGRpZXQgd2hlZWwifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFoOGNkbjBncGp4cW05MnM4emVybGcydDBleXY0cjB1dzVmMHJ1dCIsIm1uZW1vbmljIjoiY2x1bXAgc2hpZnQgd2VhcG9uIGFjaGlldmUgbnVjbGVhciBuZWNrIHJhdyBnZW51aW5lIHdlZGRpbmcgYm90dG9tIHJpY2ggbmVnbGVjdCBpbnZlc3Qgd2FsayBzb25nIGNoZWYgdW5oYXBweSBwYXVzZSB3aXRuZXNzIGFydCB2YXVsdCByaXR1YWwgZnJpZW5kIGRpZ2l0YWwifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE5eXhqM3AwMjZmcGs0NjBleGwybDJyMnVsZ2czbjdkbnl3czB0OCIsIm1uZW1vbmljIjoiYnVua2VyIG9yZ2FuIGdyb2NlcnkgdHJhbnNmZXIgc2FsdCBlbnRpcmUgYWRtaXQgZ3VhcmQgaWxsZWdhbCBzdGFpcnMga2ljayBjb2x1bW4gZm9yY2UgdmlvbGluIGNsb2NrIGhhbmQgcHVyY2hhc2UgdGFnIGZhdGlndWUgdW52ZWlsIHNpbGx5IGlkZWEgcmF6b3IgZmFuY3kifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE5MnN4enZ5ajYyNXB0ajQ1ZjAydmdlc2x5eG5tYXh3dHlxbmVyOCIsIm1uZW1vbmljIjoiYXJyYW5nZSBzdGVwIGhlYXZ5IG1pc3Rha2UgZmF0aGVyIGJ1bmRsZSBjaGF0IGRlc2NyaWJlIG1hZCBzZXR0bGUgZWFzdCBicmVlemUgdXNlIHdhcnJpb3IgZ3JhcGUgbnVyc2Ugc2F0aXNmeSBuZXN0IHRhcmdldCB2aWNpb3VzIGNvc3QgZ2VudGxlIGVtYm9keSBhbnN3ZXIifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF5NXI3MzhuZnFzNnZseDc2MnM1OGdya3o1dzJycGp2amRoc2ttNCIsIm1uZW1vbmljIjoicmVzaXN0IGVubGlzdCByaW90IHNvbGlkIGxpZnQgZnJvbnQgc3F1ZWV6ZSBhZmZvcmQgbGlxdWlkIGJvbmUgbWF4aW11bSBkb29yIGhhemFyZCBmcmllbmQgcGFkZGxlIHBhZGRsZSBodWIgcmVnaW9uIHNwcmF5IGZpdG5lc3Mgb3JkZXIgdGlzc3VlIGJldHdlZW4gdW5rbm93biJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE0amRmMzM2cmZ1bmVobjZjNDZuemZ6N2YyMzh5NWFsczlnajc3NSIsIm1uZW1vbmljIjoiYWN0b3IgaW50byBtYWtlIHNvbWVvbmUgcGF0aWVudCBjaXZpbCBwbHVuZ2UgYnJhY2tldCB3ZXQgbG92ZSBlbnJpY2ggYW1vdW50IHB1bHAgdmljaW91cyBhd2Vzb21lIGxvZ2ljIG96b25lIHRoYXQgZml0bmVzcyBzaG9wIGJldHdlZW4gZGlub3NhdXIgbGVuZCBsYXRpbiJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFlMm55czk4ejdoa2V4bDJxOWs4eHk5ZzkyejlsbGx2a3gwcHB4cCIsIm1uZW1vbmljIjoiYWNpZCBhbm90aGVyIGF0b20gaW5kb29yIGR5bmFtaWMgdml2aWQgY2hpZWYgbWlsbGlvbiBkeW5hbWljIGJlbGlldmUgdG9kZGxlciByZWxpZWYgYWNoaWV2ZSBhYmlsaXR5IG1lbW9yeSBjb21tb24gc2x1c2ggcmVhc29uIG5vYmxlIG5vYmxlIHF1YWxpdHkgZG92ZSBob2xsb3cgcmVxdWlyZSJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFrdHI3dnc5aDU4ZHo1MDVwazY4cXNjZ2xtdnM5OXVsbmVqZ2ZjOSIsIm1uZW1vbmljIjoiY29uZ3Jlc3MgYnJvY2NvbGkgc3RheSBwZW4gY2hvaWNlIHBhdGNoIHNldmVuIG1hbW1hbCBteXN0ZXJ5IGRpenp5IHdlZWtlbmQgc29sdmUgaW5zYW5lIGN1cCB3YXkgdXNlZnVsIGhvdXIgbGF1Z2ggZ3JvY2VyeSBhbmltYWwgYnJpZ2h0IGZvbGQgY2xpbmljIGRpY2UifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF6bHE5czdtcnZ5c2hhN2g5dHB1MjQwYzYwd3k3MDNyemMzeDJsNiIsIm1uZW1vbmljIjoicmFkYXIgYXJ0aXN0IGZpbGUgcHJvdWQgcGFyZW50IGhhcmJvciBjYXIgdmFyaW91cyBnaG9zdCBtYXJrZXQgbWFycmlhZ2UgZGVtYW5kIHVzdWFsIGFubnVhbCB3aWRlIHNtb2tlIGRpcnQgY3JvdWNoIHNlY3VyaXR5IGljb24gcHJhaXNlIHRvbmlnaHQgcG9ydGlvbiBjYXZlIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFqOXo3dHlhbHprZ3ljZ3ZtaHZmYXIwYWh2eTdhMDJmejcyOXhhdSIsIm1uZW1vbmljIjoieW91IGRpc2Vhc2UgdG9yY2ggY3Jvc3MgdmVyc2lvbiBtb25zdGVyIHNwaWtlIGZldGNoIHBhdGNoIHZpbnRhZ2Ugc2tpbiBmYXZvcml0ZSB3aW5nIGZhY3VsdHkgcmVjaXBlIHF1aXogYWxsb3cgcmlnaWQgcGhvbmUgdGFibGUgaG9ybiBmcmllbmQgd29sZiB2aW9saW4ifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE3MzU1czZ5NzQ0bDgyd3BreDQ5cWxycnQ4amw3dXVoYTkwejcwdiIsIm1uZW1vbmljIjoic2hvb3QgdW5kbyBlbnRpcmUgZmxpcCBvcGVuIGNhdXNlIG9uZSB0b3BpYyByb3VuZCBwdXQgZGV2ZWxvcCBpdGVtIHBvd2RlciBjdXNoaW9uIHdhZ2UgcmV0dXJuIHBpZWNlIGRpdm9yY2Ugc3RlbSBzYXRvc2hpIHByb3NwZXIgc3RhYmxlIHZvY2FsIHNob3ZlIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFmdmh4a2Rsbm50aDRhdnRyOXljeHUwMmpjdHB6czZzZzhhM2w1eCIsIm1uZW1vbmljIjoic2NvcnBpb24gbmFpdmUgZHJlYW0gdGFzayBleGNoYW5nZSBkcnVtIGdyb2NlcnkgZGVncmVlIGhlYXZ5IHByZXBhcmUgZ3JlZW4gYmxvc3NvbSB2ZW51ZSBzeW1wdG9tIGlsbCBwZW9wbGUgbWFqb3IgemVybyBob25leSBvYmxpZ2UgY2VtZW50IG5ldHdvcmsgcmVuZXcgYm9uZSJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE4ZXlyYXpha2F5Nmo1eWhmcHZ4ZDJwdjV4ODBqcHlxOXFrdGZwMiIsIm1uZW1vbmljIjoicm9tYW5jZSBpbmNvbWUgbmV0IHNwbGl0IHJlbmV3IG1pbWljIGpva2UgY29ycmVjdCBhZ2VudCBqb3VybmV5IGxlbnMgYWltIG1vdGhlciBjYWdlIGFzcGVjdCB0cmFwIGJlbGlldmUgdGhyaXZlIGRhbmdlciBtYXRjaCBjcnVtYmxlIGFkdmljZSBhZGRpY3Qgc2NhdHRlciJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF4ZnlodjN2ejZkeW5zMnBneXBtcTRwbDhzMmVyYWFlazB3ZjB1NyIsIm1uZW1vbmljIjoiYnJlZXplIHBldCBwaWFubyBlY2hvIHJpc2sgZGlzbWlzcyBwb2VtIHRoZXkgc2FkbmVzcyBhbWF0ZXVyIG1pbm9yIGNvcHkgcHJpZGUgcXVhcnRlciBhbm90aGVyIGVtZXJnZSBtZWFkb3cgcmV1bmlvbiBleGhhdXN0IHNhbHQgbG9jYWwgbWV0YWwgZGVjYWRlIHZpc2l0In0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE0cHI1N3dnN3gzamw2bmFlODRqd21hbTA2eHBjd2RzdXdjdHF2biIsIm1uZW1vbmljIjoiYW1hdGV1ciBnb2xkIHdvbmRlciB0aXNzdWUgbGVnIHByaWNlIGdsYXJlIGxpbWIgbGl2ZSBmb2lsIGRlc2lnbiByaWdpZCBnb2F0IGNlcnRhaW4gY3Jvd2Qgd2hhbGUga25vY2sgcHJpbnQgcHJldmVudCBzdG9vbCBhdXRvIG1hcmJsZSBnbG9vbSBzY3JpcHQifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF0OHMwODY0Y2V1ZWF6Zjl4bHF5MHh3ajRhOHh0ZWM4cmVkNm1mNSIsIm1uZW1vbmljIjoidG9zcyBjbHViIG1vcm5pbmcgZ3Jhdml0eSBpc29sYXRlIGpvYiBsZWFmIGNsYXkgbGFiIGRyeSBsaWZlIHVudXN1YWwgcHVkZGluZyB2aXZpZCB0YWlsIHBlbGljYW4gdmlzYSBhcnJvdyB3ZWVrZW5kIGtpZG5leSBhbmFseXN0IGFiaWxpdHkgZXF1aXAgbmFycm93In0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFyazN3YWZ5ajZhaDY5eWRsbWtuc2pla3ljdTYwamo5MnRobWFuMiIsIm1uZW1vbmljIjoiZ2x1ZSByb3lhbCB3cmVjayBiZWVmIGFjaWQgdHJpY2sgZ3Vlc3MgYWJzdXJkIGZsYW1lIGNvbW1vbiBjb3JuIGNhc2UgY2hhdCBhdHRpdHVkZSBhZGRyZXNzIHdhbG51dCBleGFtcGxlIHJpZ2lkIGtpd2kgbGVhZGVyIHJpbmcga2lzcyB0ZW50IGRpZXQifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFjc3J1ODg5YXlkcDdhenE4dWo1eGt0a3NwempudmtnbnF3dXY5eiIsIm1uZW1vbmljIjoiZGVicmlzIGZlYnJ1YXJ5IHN0b2NrIGh1bWJsZSBjaGlsZCBndWlsdCBzdGVtIHN0eWxlIHdlZGRpbmcgZnJvZyBkYXVnaHRlciB0b29sIGhvbGxvdyB0ZWFjaCBiaW9sb2d5IGFyb3VuZCBzaWRlIGRlYWwgbG9ic3RlciBjdXJ0YWluIG5lc3QgcXVhbnR1bSBjb21iaW5lIG1pcnJvciJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFhcjVqcGowMzJrYW1oOG40cmRweGR3amhhbXZja2dtejk4d2RtMiIsIm1uZW1vbmljIjoibWVtb3J5IGluanVyeSBvcGVuIG1vbml0b3IgdHVubmVsIGlsbG5lc3MgZGVyaXZlIG9yYW5nZSByZXN1bHQgZGl2ZXJ0IGtpZG5leSBodXJ0IGh1bW9yIGJlY29tZSBhcmd1ZSBidWxiIG1vc3F1aXRvIHRvcHBsZSBiZXN0IGRlY3JlYXNlIHVzdWFsIGxlZ2VuZCBwaXN0b2wgZWl0aGVyIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFjYWZnbDl1d21uemxhbXh3cjZwdHhocGhlNzM5bjVjamgydjQ3bSIsIm1uZW1vbmljIjoic2lnaHQgZGF1Z2h0ZXIgdW5hYmxlIG1vdXNlIGJyaW5nIHNpbGx5IHNldHVwIHZpZXcgYmVlZiBkb3ZlIGx1Z2dhZ2UgYWlycG9ydCBnYW1lIHR3ZW50eSBzaWx2ZXIgZWxkZXIgY2xvZyBtZW50aW9uIGtpdGNoZW4gZ2FyYmFnZSBhaXIgcGF0aWVudCBkZXB0aCBjaG9vc2UifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEzcW52anN2MHN2eWs5Y25sZjBoMGdmbDl4dXY1OW5jc3NmN3ZqdyIsIm1uZW1vbmljIjoiZWxpdGUgc2hpZWxkIHBsYXRlIHB1enpsZSBlZGdlIHNvZnQgY29ycmVjdCBhbmFseXN0IHNhbG9uIGhhcmJvciBzaG92ZSBjdXN0b20gc3VzdGFpbiBsYXVuZHJ5IGthbmdhcm9vIG1vdmllIHdyZWNrIGNsb2cga2lzcyBidXJkZW4gYmluZCBpbmZsaWN0IHVzZWQgYXJlbmEifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEzemRlNTRndTR0cmFzaHdxdHFrbW05N2xuOGVyNmV4enhmbTB1ZiIsIm1uZW1vbmljIjoiZXJyb3IgcXVpdCBmaXggZHVtYiBodXNiYW5kIGNlcmVhbCBzd2ltIGJ1YmJsZSBqdW5pb3IgYnVzaW5lc3MgcmVxdWlyZSBncmFpbiBwdWRkaW5nIG51bWJlciBmYXVsdCB0aGluZyBjZWlsaW5nIGluZmxpY3QgY2hlcnJ5IGN1cmlvdXMgZ2luZ2VyIHJlY29yZCBub3J0aCBnZW5yZSJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFrM3FlcGNseTNueHgzd2psZ2o3ODNobGpldXdqdjVkcjAwNThwdCIsIm1uZW1vbmljIjoiZ2lyYWZmZSBvd24geW91dGggc2hpcCBsZW5zIHNuYXAgcGl0Y2ggcmFpbiB3ZXN0IGV4aGliaXQgYXhpcyBncmFpbiBncml0IHZhbGlkIHZlcmlmeSBzbGFtIHBsdWcgY2FudmFzIHBheW1lbnQgY29zdCBhbG1vc3QgZXhjZXNzIGRlZ3JlZSByYXRlIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE1MDNxNjZzaG16NDZ5NXR1bWN5dW1lbDdyeWw1ZXhycmgzZThyNyIsIm1uZW1vbmljIjoiZm9sZCBnZXN0dXJlIGNvbmdyZXNzIHJhdGUgcGxhc3RpYyBtaW5pbXVtIGhlYWx0aCBzZXR0bGUgY3J5IG9iZXkgbmV2ZXIgc2VyaWVzIGJsYWNrIGtlZW4gc2FpbCBmcm9udCB0eXBlIGZ1cnkgY3J1ZWwgdHJlZSByZW1pbmQgb3JiaXQgdG93YXJkIGZsdWlkIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFrM3R4M3VuMnM4ZXNyams0MDR0cDNuencyYXk1N25kOWN2Z2ZoeSIsIm1uZW1vbmljIjoic2Nob29sIHBlbmNpbCBtdWNoIHRhcmdldCBlbmdpbmUgdXBvbiBzbWFydCB0cnVzdCB3YWdvbiB2ZW50dXJlIG1vZGVsIGFkYXB0IGF0dGVuZCBwdXJwb3NlIGZhY3VsdHkgaHViIHBsdWNrIHZveWFnZSByYWRhciBtaXJyb3IgdmlzaXQgdHJ1bHkgZXhjaGFuZ2UgY2VtZW50In0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE5ejNudWowemZkZ2Z1a3hlYzNsNHNxaGRyZ3kzOG1qdHJscHdhMiIsIm1uZW1vbmljIjoibWVhbiBjbGllbnQgc2NhbGUgY29uc2lkZXIgc291bmQgYmVmb3JlIHJlbWVtYmVyIGVydXB0IHBpdGNoIGljZSBob3JuIGF0dGVuZCBwYXZlIGN1cmlvdXMgcHJlc2VudCBzYWlsIGFpbSByZW1pbmQgdmFsbGV5IGZhdGhlciBzaGlmdCBjYW4gc3RheSBjb29sIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFubXVjYW1hNnVmc2tsdDg2YWNoeG5lZGgzajlkZmd2MmpydmU0NiIsIm1uZW1vbmljIjoidG93biB3aW5kb3cgbG9ic3RlciBwYW5pYyBleGhhdXN0IHByaW9yaXR5IHRpbWUgdmlydHVhbCBjYXJ0IGRyZWFtIHNjb3JwaW9uIHJlcGxhY2Ugb3V0ZXIgd2hlYXQgdW5hYmxlIGFsbGV5IGdhbGxlcnkgc2Npc3NvcnMgY3JldyBnYXRoZXIgbXVjaCBzbGVlcCBhd2FyZSB0YWxrIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEwbTNjdng1ZXA1MHBkeWpscDVlOWVyMnE5NG5oaG01aGc4aHY2cSIsIm1uZW1vbmljIjoicGFsbSBkZXNlcnQgcmVvcGVuIGdpYW50IHRoYXQgb3JwaGFuIHRoZXkgbGVnZW5kIGZyb3N0IHBsdWcgdHdlbnR5IGJvbWIgY3J1bWJsZSBnb3Zlcm4gZW50ZXIgY2FzdGxlIG5lc3QgdGFzdGUgYWJ1c2UgcGVuYWx0eSByYW1wIGltYWdlIHRhYmxlIHRvcHBsZSJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFrbXZubnN2bW0wd2RkcGEyZTd6bDRnYzgwNW0wcTZha2d2cXF6OCIsIm1uZW1vbmljIjoib2JsaWdlIHdhdGVyIHRvcmNoIGZhbnRhc3kgYnJpZWYgZGV0YWlsIHNpbHZlciBibGFjayBicmF2ZSB0YWNrbGUgcG9ueSByaWZsZSBhbHRlciBmZXZlciBsYXZhIGZhaW50IGtub2NrIGluaGFsZSBibHVlIGJlYXV0eSBsaXR0bGUgaGlzdG9yeSBzY2VuZSBlaXRoZXIifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE2ZDB3N20yZm5oenBsYzl6ZDV2bjJ0OWNkMHc3dDNncng2ODh4MiIsIm1uZW1vbmljIjoibWFuIGNoYXNlIHZlcmIgZGl2b3JjZSByZWN5Y2xlIHRvbWF0byBhcm1lZCBjb3ZlciB3ZWIgd2ludGVyIGRpc21pc3MgZ2xpbXBzZSBwbGFjZSBsaW9uIGNvaW4gY2VyZWFsIGtuZWUgbGluayBwb3dlciBjdXBib2FyZCBmbHVzaCBnbG92ZSBjbHVzdGVyIHN0YWJsZSJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFqdjN1c2R2aDRta2VhM3A4MHk2ZG5ud2RxNWx3bW04dTNsYXB5eCIsIm1uZW1vbmljIjoidHdlbHZlIHBhZ2UgZGF1Z2h0ZXIgY2F0dGxlIHNvcnJ5IGRpc21pc3MgZXhjdXNlIGtpbmQgcmFiYml0IG9wZXJhIHJlcGVhdCBjYW5vZSBndWVzcyB0ZXN0IGNsYXcgZmVicnVhcnkgdm9sY2FubyB0cmFwIHR5cGUgeW91IHJ1cmFsIGNoYWxrIGlubmVyIG5ld3MifQ=="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFlODV2cXJod2tqc2h0ZXZrd3U0cGpnMGFodzczc25lYzl3YWR1aCIsIm1uZW1vbmljIjoiaG9uZXkgYWxidW0gZmVlIGh1bW9yIHNvcnQgdG9tYXRvIHRvZ2V0aGVyIHJpdHVhbCBiZWFuIHdlYXIgcm91Z2ggY3JhZnQgcmV3YXJkIGlzbGFuZCBwdXJjaGFzZSB0ZWxsIHJpdmVyIHJldHVybiBzd2FsbG93IHZvbGNhbm8gc3ByaW5nIHNwZW5kIHdlbGNvbWUgYnVuZGxlIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEyOHU2OWVucXdjZnF4bWFkZXE3eXhmODZhNjY0aDRxd3k5dHU0OSIsIm1uZW1vbmljIjoicGxhY2UgdHVuYSBuZXJ2ZSBjcmltZSBpbmR1c3RyeSBjb3lvdGUgaGFyZCBjdXNoaW9uIGRpYXJ5IGNoYXQgY29ybiByZW1haW4gc2Vuc2UgbHVnZ2FnZSBsb2NhbCBob3JuIHRpbHQgZm9zdGVyIGluY2ggd2ViIGV4dGVuZCBhbHRlciBkaWxlbW1hIGV4Y2VzcyJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFhcDk2bmowaG1wdXZod25wdXByeGM0Z3hyZ2dsMnN5MzB6YTI4biIsIm1uZW1vbmljIjoidHJ1dGggYmluZCBnYXRoZXIgbG9ic3RlciByb3RhdGUgYmFyZWx5IHZvbHVtZSBoYW1zdGVyIHJpZ2h0IGxlbW9uIHBvbGFyIHZlc3NlbCBtZW1iZXIgY29tZm9ydCBsb2FkIGJyYW5kIG9hayBtaW5pbXVtIHByZWZlciBjcm91Y2ggZ2FkZ2V0IGluZmFudCBjYXV0aW9uIHN0aWxsIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFtOHB1bTJuNXI5dXJsaGZzaHNqc3FlbDB1NzdobGNxcmMyYXJhZiIsIm1uZW1vbmljIjoiZXhwcmVzcyBzY2llbmNlIGV4Y2l0ZSBoYW1tZXIgdGFzayBnb3NwZWwgcmVncmV0IGltcHJvdmUgc3BpZGVyIG5ldCBjYW4gc2VjdGlvbiBzYW1lIGFwcHJvdmUgc2NyZWVuIGlkZWEgYmFsY29ueSBvdmVyIHNlbnRlbmNlIGJpcnRoIGdhbWUgbWFyaW5lIHZveWFnZSBiaW5kIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFwNjc0cnpsOGtsdHhlNjR4MG5rbXF3ZXhnOW13bXpuOWZuc21hciIsIm1uZW1vbmljIjoiYmFieSBidWxsZXQgbWVsb2R5IGNlbnN1cyBoYXJ2ZXN0IHBhY3QgdGF4aSByZWxlYXNlIGNoYW9zIHRyYWRlIHBvZW0gamF6eiBtYWNoaW5lIGNhbnlvbiBibGVhayB0aGFuayBmdXJ5IGFzc2F1bHQgZ2F0ZSBhbnhpZXR5IGxvY2FsIHJvc2UgbW92aWUgd3JhcCJ9"), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF5YWY3c3hsd3Bscmt4MmZ5YW04em0wY3h5ZWF3em1jeDRlanp6OSIsIm1uZW1vbmljIjoic2hlbGwgc2NyYXAgZXJvZGUgbGF3c3VpdCBiYXIgcGFnZSBtZWRhbCBiaXJ0aCBjcnVuY2ggcml0dWFsIGJlbHQgYXNzYXVsdCBzb21lb25lIG5ldHdvcmsgdmF1bHQgY295b3RlIGhvbGxvdyBjYXJyeSBqdW5rIG1hZCBudXQgcG9saWNlIHVuaWZvcm0gY29sdW1uIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFqd3hua3pkOWY4OTl5ODIybW51aDJ5czQ1MGp5Z2R1bTA1c255YSIsIm1uZW1vbmljIjoiYm9ycm93IHN3ZWFyIGNhdHRsZSByaWRnZSBxdW90ZSBpbXBvc2UgYWJvdmUgbWF0ZXJpYWwgZGVhbCBwb2V0IGFsc28gY2VyZWFsIHR5cGUgdGVubmlzIHJpZGUgZGl2aWRlIGJ1bGsgcGxlZGdlIGdvcmlsbGEgZmF1bHQgY2FycGV0IHZhbiBodXJkbGUgbm9ybWFsIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF2ZTl1bmpjcWV6NnA1dWNwd2tod204YTVhdGZhMmc1N2M0eTA3cyIsIm1uZW1vbmljIjoibWF0cml4IHNraSB3YW50IGNsb3RoIGF0dGFjayBoaWRkZW4gc2FsbW9uIHRyYWRlIGx1eHVyeSBpbml0aWFsIGhhbmQgaG9zcGl0YWwgZmFpbnQgbW90aW9uIHVzZWQgdXNlbGVzcyBjYXZlIHZlcnNpb24gaW5uZXIgcmVtaW5kIGZsaXAgcm9vZiBjb21mb3J0IGxvY2FsIn0="), + mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF0bWNxY2pucjA1a2w1cHp1NXJkd3h1NncwbmxkanV1YXZ1MHBkcCIsIm1uZW1vbmljIjoic2NoZW1lIGJvdHRvbSBtaWRkbGUgYmVjb21lIGJlc3QgZXNzZW5jZSBwaWdlb24gY29uc2lkZXIgYmFycmVsIHN3YXAgZmF1bHQgc21pbGUgY2FwYWJsZSBoZWFydCBwcm9wZXJ0eSBzaXplIG9mZmljZSB1bmZhaXIgaG9iYnkgbGF0aW4ga2luZ2RvbSBnbGlkZSB0b290aCBjcnVtYmxlIn0="), ) ) From 2d52838c292c25d4f174c72299471cbdc1a5ec18 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 21 Dec 2023 19:36:26 +0100 Subject: [PATCH 12/58] fix: session hydrator --- x/session/keeper/query_get_session.go | 2 +- x/session/keeper/session_hydrator.go | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/x/session/keeper/query_get_session.go b/x/session/keeper/query_get_session.go index e8931b343..e2d4681af 100644 --- a/x/session/keeper/query_get_session.go +++ b/x/session/keeper/query_get_session.go @@ -32,7 +32,7 @@ func (k Keeper) GetSession(goCtx context.Context, req *types.QueryGetSessionRequ blockHeight = ctx.BlockHeight() } - sessionHydrator := NewSessionHydrator(req.ApplicationAddress, req.Service.Id, req.BlockHeight) + sessionHydrator := NewSessionHydrator(req.ApplicationAddress, req.Service.Id, blockHeight) session, err := k.HydrateSession(ctx, sessionHydrator) if err != nil { return nil, err diff --git a/x/session/keeper/session_hydrator.go b/x/session/keeper/session_hydrator.go index 6e56810a4..4842cf9ff 100644 --- a/x/session/keeper/session_hydrator.go +++ b/x/session/keeper/session_hydrator.go @@ -96,7 +96,9 @@ func (k Keeper) hydrateSessionMetadata(ctx sdk.Context, sh *sessionHydrator) err } sh.session.NumBlocksPerSession = NumBlocksPerSession - sh.session.SessionNumber = int64(sh.blockHeight / NumBlocksPerSession) + sh.session.SessionNumber = sh.blockHeight / NumBlocksPerSession + + // NB: SessionStartBlockHeight should be aligned to NumBlocksPerSession. sh.sessionHeader.SessionStartBlockHeight = sh.blockHeight - (sh.blockHeight % NumBlocksPerSession) sh.sessionHeader.SessionEndBlockHeight = sh.sessionHeader.SessionStartBlockHeight + NumBlocksPerSession return nil From 6a9d6ece5542e6a09ef8b499dfb06454ca338179 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 21 Dec 2023 19:36:51 +0100 Subject: [PATCH 13/58] feat: add InMemoryCosmosNetwork interface --- testutil/network/interface.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 testutil/network/interface.go diff --git a/testutil/network/interface.go b/testutil/network/interface.go new file mode 100644 index 000000000..79dc252da --- /dev/null +++ b/testutil/network/interface.go @@ -0,0 +1,30 @@ +package network + +import ( + "context" + "testing" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/testutil/network" +) + +// InMemoryCosmosNetwork encapsulates the cosmos-sdk testutil network instance and +// the responsibility of initializing it, along with (optional) additional/ setup, +// in #Start(). It also provides access to additional cosmos-sdk testutil network +// internals via corresponding methods. +type InMemoryCosmosNetwork interface { + // GetClientCtx returns a cosmos-sdk client.Context associated with the + // underlying cosmos-sdk testutil network instance. + GetClientCtx(*testing.T) client.Context + + // GetNetworkConfig returns the underlying cosmos-sdk testutil network config. + GetNetworkConfig(*testing.T) *network.Config + + // GetNetwork returns the underlying cosmos-sdk testutil network instance. + GetNetwork(*testing.T) *network.Network + + // Start initializes the in-memory network, performing any setup + // (e.g. preparing on-chain state) for the test scenarios which + // will be exercised afterward. + Start(context.Context, *testing.T) +} From 5566e5ce2e1f4fbc6fb044ae2d3ea6b9019ca7da Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 21 Dec 2023 19:37:04 +0100 Subject: [PATCH 14/58] chore: add InMemoryNetworkConfig --- testutil/network/config.go | 84 ++++++++++++++++++++++++++++++++++++++ testutil/network/types.go | 23 +++++++++++ 2 files changed, 107 insertions(+) create mode 100644 testutil/network/config.go create mode 100644 testutil/network/types.go diff --git a/testutil/network/config.go b/testutil/network/config.go new file mode 100644 index 000000000..78470f496 --- /dev/null +++ b/testutil/network/config.go @@ -0,0 +1,84 @@ +package network + +import ( + "fmt" + "testing" + "time" + + db "github.com/cometbft/cometbft-db" + "github.com/cometbft/cometbft/libs/rand" + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdkservertypes "github.com/cosmos/cosmos-sdk/server/types" + pruninttypes "github.com/cosmos/cosmos-sdk/store/pruning/types" + "github.com/cosmos/cosmos-sdk/testutil/network" + "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/types" + + "github.com/pokt-network/poktroll/app" +) + +// GetNumApplications returns the number of applications to be created in the network at genesis. +func (cfg *InMemoryNetworkConfig) GetNumApplications(t *testing.T) int { + t.Helper() + + if cfg.NumApplications > 0 { + return cfg.NumApplications + } + + return cfg.AppSupplierPairingRatio * cfg.NumSuppliers +} + +// GetNumKeyringAccounts returns the number of keyring accounts needed for the given configuration. +func (cfg *InMemoryNetworkConfig) GetNumKeyringAccounts(t *testing.T) int { + t.Helper() + + return cfg.NumGateways + cfg.NumSuppliers + cfg.GetNumApplications(t) +} + +// DefaultConfig will initialize config for the network with custom application, +// genesis and single validator. All other parameters are inherited from cosmos-sdk/testutil/network.DefaultConfig +func DefaultConfig() network.Config { + var ( + encoding = app.MakeEncodingConfig() + chainID = "chain-" + rand.NewRand().Str(6) + ) + return network.Config{ + Codec: encoding.Marshaler, + TxConfig: encoding.TxConfig, + LegacyAmino: encoding.Amino, + InterfaceRegistry: encoding.InterfaceRegistry, + AccountRetriever: types.AccountRetriever{}, + AppConstructor: func(val network.ValidatorI) sdkservertypes.Application { + return app.New( + val.GetCtx().Logger, + db.NewMemDB(), + nil, + true, + map[int64]bool{}, + val.GetCtx().Config.RootDir, + 0, + encoding, + sims.EmptyAppOptions{}, + baseapp.SetPruning(pruninttypes.NewPruningOptionsFromString(val.GetAppConfig().Pruning)), + baseapp.SetMinGasPrices(val.GetAppConfig().MinGasPrices), + baseapp.SetChainID(chainID), + ) + }, + GenesisState: app.ModuleBasics.DefaultGenesis(encoding.Marshaler), + TimeoutCommit: 2 * time.Second, + ChainID: chainID, + NumValidators: 1, + BondDenom: sdk.DefaultBondDenom, + MinGasPrices: fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom), + AccountTokens: sdk.TokensFromConsensusPower(1000, sdk.DefaultPowerReduction), + StakingTokens: sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction), + BondedTokens: sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction), + PruningStrategy: pruninttypes.PruningOptionNothing, + CleanupDir: true, + SigningAlgo: string(hd.Secp256k1Type), + KeyringOptions: []keyring.Option{}, + } +} diff --git a/testutil/network/types.go b/testutil/network/types.go new file mode 100644 index 000000000..716942c56 --- /dev/null +++ b/testutil/network/types.go @@ -0,0 +1,23 @@ +package network + +import ( + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/testutil/network" +) + +// TODO_IN_THIS_COMMIT: godocs comment... +var TestProofPath = []byte("test_proof_path") + +// TODO_IN_THIS_COMMIT: godocs comments... +type InMemoryNetworkConfig struct { + NumSessions int + NumRelaysPerSession int + NumBlocksPerSession int + NumSuppliers int + NumGateways int + NumApplications int + // TODO_IN_THIS_COMMIT: comment ... w/ the **same serviceId**... mutually exclusive w/ NumApplications + AppSupplierPairingRatio int + CosmosCfg *network.Config + Keyring keyring.Keyring +} From 923907b2d980c13c15400fa7d5e737cc7fd42e1d Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 21 Dec 2023 20:21:15 +0100 Subject: [PATCH 15/58] chore: add TODO comment --- testutil/network/config.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/testutil/network/config.go b/testutil/network/config.go index 78470f496..27d06128d 100644 --- a/testutil/network/config.go +++ b/testutil/network/config.go @@ -40,7 +40,9 @@ func (cfg *InMemoryNetworkConfig) GetNumKeyringAccounts(t *testing.T) int { // DefaultConfig will initialize config for the network with custom application, // genesis and single validator. All other parameters are inherited from cosmos-sdk/testutil/network.DefaultConfig -func DefaultConfig() network.Config { +// +// TODO_UPNEXT(@bryanchriswhite #285): Remove _ prefix after DebugConfig is removed from network.go. +func _DefaultConfig() network.Config { var ( encoding = app.MakeEncodingConfig() chainID = "chain-" + rand.NewRand().Str(6) From 8b57b22b5ebeccb74898a342a8db89b6756ef2b0 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 21 Dec 2023 21:10:25 +0100 Subject: [PATCH 16/58] Revert "fix: pre-generated keyring accounts" This reverts commit af531b08dae7e76ce68d7605a6ce70e3e376d0bc. --- testutil/testkeyring/accounts_table.go | 202 ++++++++++++------------- 1 file changed, 101 insertions(+), 101 deletions(-) diff --git a/testutil/testkeyring/accounts_table.go b/testutil/testkeyring/accounts_table.go index f8d9d3bd9..711a25018 100644 --- a/testutil/testkeyring/accounts_table.go +++ b/testutil/testkeyring/accounts_table.go @@ -1,111 +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_testgen_accounts or go generate ./testutil/testkeyring/keyring.go. +// To regenerate this file, use make go_testgen_accounts or go generate ./testutil/network/keyring.go. package testkeyring var ( preGeneratedAccounts = NewPreGeneratedAccountIterator( - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF2N2VwZ3JzNmRjNjdrMHQweHZ2dHFleWVqaDlwbWpucHR1ZnFkZCIsIm1uZW1vbmljIjoiZGF1Z2h0ZXIgaHVtYmxlIG1vdXNlIHBlcnNvbiBodXNiYW5kIHdhc2ggZm9sZCBwbGFzdGljIG9ic2VydmUgbmF0aW9uIGZhdGhlciBwYXJ0eSBoZWFydCB3ZWVrZW5kIHllYXIgYWR1bHQgc3RyaWtlIGZsYW1lIGJhciBzaG9lIHZpYnJhbnQgaGFyYm9yIHJlcGVhdCBjYWJsZSJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFrODJtdThtZDNyOWc1M3BhNGxldGFnM2owZnoyMjlmemNxZGhodiIsIm1uZW1vbmljIjoic2VtaW5hciBpbnRvIHNuYWNrIGhhdCBzdGVlbCBzaWxseSBnbGFzcyBlbWJhcmsgd2Vla2VuZCBzbW9rZSBnaW5nZXIgd29sZiBzY3J1YiBnaXJsIG9seW1waWMgd2FzdGUgZXh0ZW5kIGx1Y2t5IHN0YXkgbWFyaW5lIGxlZnQgbGVhZGVyIGNvbWljIGltaXRhdGUifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFjcXZyM3Q3NGFhbncydzRjMzh3OWhwNzNwY2w4c2s2ejZlZmdkZSIsIm1uZW1vbmljIjoiYnVkZHkgc3BvcnQgYWdlbnQgbWVyZ2UgZGVwdGggcGVuIHNheSBmb2N1cyBkaW5vc2F1ciBjaXRpemVuIGFnYWluIG11Y2ggbWFuZGF0ZSBpZGVudGlmeSBkZWZ5IHJvYXN0IGxpYnJhcnkga2ljayBhbXVzZWQgdGhyb3cgc2xpY2Ugc2VlZCBkb2N0b3IgY29tZm9ydCJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFxZXJ0c2t2bmFuZTJmN215bWQ4cWY5aHpzbWU2bGx5cW16d3BrYSIsIm1uZW1vbmljIjoic2NhdHRlciBzdHVtYmxlIGJhc2Ugc2hpbmUgc2lsZW50IGNlcmVhbCBzaGFsbG93IHdhaXQgc21pbGUgZHV0eSB0b21vcnJvdyBwYXBlciB6b25lIG5hcnJvdyBkZWZlbnNlIGdlbnRsZSBiYXIgZW1wdHkgcG9ldCBzdGFtcCBkb21haW4gYnV0dGVyIHBldCBsYXVnaCJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFxZTJscTBkenN2YXV1OXlrdnh2NnhncGtraHVnNHd5cmRrMnh6OSIsIm1uZW1vbmljIjoiamFja2V0IGZsZWUgd2FyZmFyZSBhY2Nlc3Mgc3dpbmcgc2lkZSB0cmVhdCBleHBhbmQga2l0Y2hlbiBvZmZpY2UgcmFtcCBkaWNlIHBvc2l0aW9uIHdoaXNwZXIgbWluaW11bSBsaWNlbnNlIHN0aWNrIGF1dHVtbiBlbmVteSBzdXN0YWluIGJsdWUgaGFsZiBzd2FtcCB2ZWx2ZXQifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFycG44dnZhZjl6ZXYyc2owcHBlZnYzbGVxd3o0YWp3YWR1bGhyeiIsIm1uZW1vbmljIjoiZmF1bHQgcmF3IGNhc2ggcGF0cm9sIGJsdXIgbGVucyBtb3JhbCB3aGVlbCBiZXRyYXkgY2FsbCBrZWVwIHJlcXVpcmUgZmF2b3JpdGUgc2VtaW5hciBibGVzcyB1c2FnZSB3aGVyZSBzdXByZW1lIGZyZXNoIHBvZXQgc25hY2sgaGFsZiBzcGlrZSB0d28ifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF5ZWFjNXEzcHd0YXlmZnRqZGRjNmE0Y3R4N3R3bDB3Y3JweHE5NCIsIm1uZW1vbmljIjoiYWJhbmRvbiBraXRlIHByaWNlIGNhcnJ5IGFybSBmb2xkIHN5bWJvbCBzcGlkZXIgY29udmluY2Ugb3pvbmUgZnJvemVuIGNsb2cgdGFsayBteXRoIGVsZXBoYW50IG5lYXIgYmFzaWMgdHJ1bHkgZG9sbCBjYXR0bGUgZ2FsbGVyeSBidWJibGUgcm9vZiBzYWRuZXNzIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF6OGUybjR5cmRnZG42cjA3M2pzdWN5YTM4Y2c0ZjlxdGhkczA0MiIsIm1uZW1vbmljIjoiZWRnZSBsb3VuZ2UgbHVnZ2FnZSBwYXR0ZXJuIGRyYW1hIGludG8gdW5mb2xkIGFjaWQgZmFtaWx5IGJleW9uZCBuaWNlIGRyZWFtIGNsb3VkIGhhcnZlc3QgZmFybSBqb2luIGVtYm9keSBwYWN0IG93bmVyIHNob2Ugc2VsZWN0IGNlbnN1cyBzcHJheSBydWJiZXIifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE2ZW41d2Q0azQ3cTNndHBuZzRkYWN6c2FodGxzMDh3dWcweDdwOCIsIm1uZW1vbmljIjoidGVuYW50IGNhc3RsZSB0d2luIGFsc28gY2VtZW50IGRyYXN0aWMgbW90b3IgdmVyc2lvbiBtZWFuIGh1bWJsZSBwZXBwZXIgc3Rvb2wgaG9vZCByZWR1Y2UgaW5mbGljdCByZXF1aXJlIG9ibGlnZSByYW5nZSBib3ggc3BlbGwgYnJpc2sgYWRtaXQgc2xvdyB0dXJ0bGUifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEyOG5md2xqOTdzYWVsenhrdTR4Mmw4NWNxN3oybWNkZHY3Y2EyZCIsIm1uZW1vbmljIjoib3V0c2lkZSBtaW5kIHNpc3RlciBub3JtYWwgcHJvYmxlbSBzYWxvbiBzcGVsbCByZWNvcmQgaW5oZXJpdCBvYnZpb3VzIHN0YXRlIHNvbHV0aW9uIHNwZWVkIHVwc2V0IGJvaWwgY2FrZSB2aW50YWdlIHRyeSBzb3VyY2UgbGVnYWwgc291cCB0cmFnaWMgY29sb3IgdHlwaWNhbCJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF0NjZ1MmQ1endzemE3Mm5ycHl0ZGw5eDU2YXRhczI3eWVwZTllZyIsIm1uZW1vbmljIjoiZ29vZCBzaG9lIGhlYXJ0IGFpciBuYXJyb3cgY2xlYW4gdXJnZSB0aXNzdWUgZnJlcXVlbnQgdGVzdCB3cmlzdCBwb255IHNvY2NlciBwdWRkaW5nIGhvbmV5IGplbGx5IG1ldGhvZCBvcmRpbmFyeSByZWNlaXZlIGxvbmVseSBnbG9vbSBjaGVhcCB0cmF5IGxvZ2ljIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF6NnFlOTgyMmRzdnBncDRqbXcycG4zMjRzc2U2cmh3MDB3M3UzZyIsIm1uZW1vbmljIjoiYW1vdW50IGRlbWlzZSBnb3duIHNjaXNzb3JzIGNvbHVtbiBnaXZlIGh1cnJ5IGNyb3NzIGh1Z2UgY2xpbmljIHRyYXkgYmFzaWMgcGVuYWx0eSBkaW5uZXIgYnJpbmcgZWNvbm9teSBjYW5keSBhc3N1bWUgZGlzdGFuY2Ugb2ZmZXIgc2FkbmVzcyByaWdpZCB3aGVhdCB0aG91Z2h0In0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFwZGpsaDVtNWxxdHRoeDNucGd3anVnNnl4NzAyZjRneHFhc2RoMiIsIm1uZW1vbmljIjoiYWhlYWQgc2NhcmUgYXNrIHBhbG0gbWF0ZXJpYWwgZGVmaW5lIHNraSBleGhpYml0IGdsaW1wc2UgZ3Jhc3MgYnJhaW4gc2FkbmVzcyByZXNlbWJsZSBhdXR1bW4gZGVwYXJ0IHNsZWVwIHN0dW1ibGUgb2ZmZXIgY29uZHVjdCBmcmFtZSBpc2xhbmQgY2lyY2xlIHN0b3J5IGhhdmUifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF0eTUzanJ0YzN6NWN0cWdwd21wZmo2ZDVyNHZyZXA3d3J3NmFldiIsIm1uZW1vbmljIjoianVkZ2UgZnJhbWUgc2llZ2UgYWxjb2hvbCBvdXRwdXQgdW5pcXVlIGJvb3N0IGNvcm4gY2FnZSBvZG9yIGh1YiBhdWd1c3QgYXdha2UgbGF2YSBjb2FjaCBvYmplY3Qgc3VyZSBzdWdhciBwb25kIGNydWlzZSByYW5jaCBnb29zZSB3aGVuIGVtYm9keSJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFrdzNoZnJzcGo1dTVjMGdnOXUzMjAzcWttOHkyOHo1bnNmNDJuciIsIm1uZW1vbmljIjoiYXJyb3cgcG9saWNlIGFub3RoZXIgaWxsbmVzcyBvdmFsIGNlbGVyeSB0d2ljZSB0b3NzIHByb2Nlc3MgYXJyaXZlIGZlZSBzcHJheSBicm9uemUgcmFuZ2UgbGVtb24gZm9yZ2V0IGludG8gZ2VudGxlIGNsdW1wIGRlY2VtYmVyIHZlc3NlbCBtaW1pYyBub3JtYWwgaW5jbHVkZSJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF0bTZ2NjllNmpqbWVzY3Z2cDhqZ2s2OHo0MnhtczYzeXZ2cXY5diIsIm1uZW1vbmljIjoic3Ryb25nIHNpc3RlciB2ZWx2ZXQgdmVyc2lvbiBpbnNlY3Qgc3VmZmVyIHVuYXdhcmUgZWNvbG9neSBwbGFjZSBzY2F0dGVyIGFjaWQgb3JwaGFuIHNvbGlkIGRlY3JlYXNlIG5vaXNlIGdlbml1cyBvYnZpb3VzIHR1YmUgY2xhaW0gbWFnaWMgdGFsZW50IGJvc3MgaGludCBzaGVyaWZmIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE4MDRrcXZscjRhcHdsYXR6Mmw5bHR3MGx2Y2pyaHQ3ZWo5dHQyNiIsIm1uZW1vbmljIjoiaG9iYnkgdXNlZnVsIHJhdGUgdHViZSBvbWl0IHJhY2UgZ2xhc3MgcHJlZmVyIHNvZnQgdGVuIHByZXNlbnQgc291bCBsYXduIHJ1ZyBpbmR1c3RyeSBzYXRpc2Z5IGdyYXNzIGZvc3NpbCBhcm91bmQgY2F0IHJvYm90IG11c3QgY3J1ZWwgZXJhc2UifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFsa2NhOGo2OXBwbWpzbTVlOHJmamZrcTAzOGx0endtYWhydXUyZCIsIm1uZW1vbmljIjoiZGFyaW5nIGRpZXNlbCBibGVzcyBzY2lzc29ycyBwcm9maXQgZmVicnVhcnkgaWRsZSBvd24gZmFicmljIHBhcmVudCBkaXNoIHBvcHVsYXIgYmVoaW5kIG1lYWRvdyBsZWFmIHB1cnNlIG1pc2VyeSByaWIgc2VydmljZSBkZXB1dHkgd2FsbCBwaXN0b2wgYmlvbG9neSBub3cifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFua3NhdDZtcjY4dXBldHMyd21kNWdnMHdwdTU3cHZrcms4OW54bSIsIm1uZW1vbmljIjoidmV0ZXJhbiBndWlkZSBmYXRpZ3VlIHBpb25lZXIgaGludCB0YWNrbGUgc3B5IHRveSBhaGVhZCB0cnVseSBob21lIG5laXRoZXIgZGFtYWdlIGxlZ2VuZCBhZG1pdCBzbGFiIHN0dW1ibGUgZmFtaWx5IGluaGVyaXQgZmx1aWQgcGx1Y2sgbWFpZCB3aWxkIHRvaWxldCJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFyY3g5amV4MG5wNzNkbjV3emNsa2tta2Z6NGptbnhlNzhqeWxqOSIsIm1uZW1vbmljIjoicmVzcG9uc2UgYXVjdGlvbiBibHVzaCBzb21lb25lIGNyb3VjaCBkaWFtb25kIGZvY3VzIG1hdHJpeCBjYWJiYWdlIHRyaWFsIGJyaWdodCBjYWdlIHdyaXN0IHBlcmZlY3Qgc2llZ2Ugc3BhdGlhbCBzcG90IGNyaXNwIHdlYiBkcm9wIGV5ZSBkaWduaXR5IG9wZW4gcm9hZCJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFjcjJqOTYwaDQya2pzY3NjdDBqaGxwdzJxdGVzamMwenR6eTIybiIsIm1uZW1vbmljIjoiYXdmdWwgdHVpdGlvbiBjcm9zcyBlYWdsZSBuZWVkIHNpemUgc2l4IHJlY2FsbCBkaWFtb25kIHRhc2sgYnVkZ2V0IHNpZWdlIHNpZ24gY3JhbSBtYXJnaW4gd2FzdGUgZXhoaWJpdCBiYWNoZWxvciBjYXVzZSByb3NlIGRyYWZ0IHNwcmluZyBvbGQgdGlkZSJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFjczN3bWU1cHY4aGZ0N3RobWE5d3pjenRtZ3g3Z2d2dXo2c2R4bCIsIm1uZW1vbmljIjoiZGV2aWNlIGZyb3duIGx1Y2t5IHJ1bGUgcmViZWwgc2VyaWVzIGVtZXJnZSBtaWxsaW9uIHJvY2tldCB3b3JsZCBwcmljZSBjYW55b24gYWJzdHJhY3QgY2hhbXBpb24gY2hhbGsgd2V0IHJlbWVtYmVyIHByYWlzZSBnaXZlIG1vbml0b3IganVuayB0YXN0ZSBpbmRleCBzY2FuIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFlbjBucjYyZHN4bmxuMmZ3M3RwbGVmcWpmM2VhZG45aHBzdmQ4MyIsIm1uZW1vbmljIjoib3JjaGFyZCBlcnVwdCBhbGFybSBzaW1wbGUgZ2FzIHRyYW5zZmVyIHRyZWF0IHdvbGYgbGltaXQgZ3VuIGRyaXAgcmVtYWluIGp1aWNlIGVuZm9yY2UgcmFuZG9tIHZlbHZldCBwaXN0b2wgc3ViamVjdCBzdGlsbCBkaWV0IHJlc2N1ZSBzcGlkZXIgcG93ZXIgbXVzY2xlIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE3eXB0djZwcHd0a21nMDZnbnphNmp1cTZmYWRqNGhycncyMG5jcyIsIm1uZW1vbmljIjoic3VycHJpc2UgcGFycm90IHNsdXNoIGVuam95IHNvbHZlIHNldmVuIHNwYWNlIGJlY29tZSByZXRpcmUgaG9ybiBsZWdlbmQgcGlnZW9uIGNoYWxrIGdsb2JlIHJ1cmFsIGx1Y2t5IHNlYSBicm9vbSBjYW5hbCBidW5rZXIgZ3JvdyBhdWRpdCBzb2xpZCB3cmlzdCJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFjd3Zuc2w1ZDJ5empwZmQzbDR2OWtwbjdsaHE3ajNyOXA1eDV4eSIsIm1uZW1vbmljIjoiaHVtb3IgcmV2aWV3IHRlYW0gZGVwYXJ0IGNhbXAgc2ltaWxhciBjdXNoaW9uIHF1aXogaW5kaWNhdGUgZ2x1ZSB2aXNhIHBpbGwgZXJhIHN0YWdlIG1ham9yIHJvbWFuY2UgcXVpY2sgc3VyZSBkeW5hbWljIGNsYXcgaW5kb29yIHZhbGxleSB0cmFuc2ZlciBmaXRuZXNzIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFwaGY4YWwzdW5obXB2M2xmemFneXdlcXRmbHM4NHpoazI5MzdxOSIsIm1uZW1vbmljIjoiZW1icmFjZSB3ZWFyIHRydW1wZXQgZWZmb3J0IHBvbGFyIGFycmVzdCBodXNiYW5kIGdlc3R1cmUgZGlubmVyIGluZGV4IHRhYmxlIHByaWRlIHZlcnkgY3JvcCByb2JvdCBjYXJkIHNwaWNlIG1hdGNoIHNrYXRlIGFydHdvcmsgYmlrZSBtZW51IHRlbm5pcyB0aWx0In0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF2MjJrcjQ1OG5zZWd5ZDRoamswd3h2N3I4dHN2ZGR1eHgwczRsZSIsIm1uZW1vbmljIjoiZmF0aWd1ZSBndW4gZG9jdW1lbnQgYXJteSB0YXJnZXQgYmFjaGVsb3IgZ2xhcmUgYnVsayByZXNjdWUgZGllc2VsIGNyYWRsZSByb2FzdCB0b2RkbGVyIHByaXNvbiBiaWtlIGJyaWRnZSBhZGp1c3QgdHJpbSBvYnZpb3VzIGNvbGxlY3QgYmx1ZSBsaWJlcnR5IHNhdXNhZ2UgY2FnZSJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF2cG5tMnBwNWZrZXhwM2tmcW52OXA2bjAwN3Fjdng1NTdqYWVsZSIsIm1uZW1vbmljIjoid3JhcCBkcmluayBjaGFzZSBhbm5vdW5jZSByZWd1bGFyIG1vdGlvbiB0eXBpY2FsIHJhdyBjYXIgbmFpdmUgZ3Jhc3MgdHJpYWwgbGVnIGJ1ZGdldCBlbGJvdyBjYXRjaCBzZW5zZSBmb29kIHJlZ3VsYXIgY3VyaW91cyBiYXNpYyBjb250cm9sIHB1bHNlIGZyaWVuZCJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFmNGtlN214NWh5M2htbnE1OTNoZGpncGp6ejVsZzhnOHpwbDN2ciIsIm1uZW1vbmljIjoicmVzcG9uc2UgdG9wIG1pbGxpb24gd2luayB0ZWxsIHRhYmxlIHJlZmxlY3Qgc2thdGUgc3F1YXJlIG1lYWRvdyBwYXRjaCByZWNlaXZlIHNuYXAgYWlycG9ydCB0dW5uZWwgcmF2ZW4gZHJpZnQgZGlzY292ZXIgYXNzdW1lIGRvdmUgdGhlbiByYWRhciBlbGJvdyBzYW1lIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFhNnR3cnFyem1tajIzdGN6d3h0ZGZ3bGo3cGh6cmd0ZnE1d2swcSIsIm1uZW1vbmljIjoiZGFuY2Ugc291bmQgZmlzaCB5ZWFyIG1hc3RlciBkZXNwYWlyIGRlbnkgc3dlZXQgY2xhcmlmeSB2b2x1bWUgdGhyZWUgY2VyZWFsIHNwb29uIGdhZGdldCBkaXNvcmRlciBzbmFjayBzb2NrIHJlZ3VsYXIgZW1lcmdlIHRvb3RoIHZpc3VhbCB2aWJyYW50IHNldmVuIGxvdHRlcnkifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF5anIwOWZzYXVwdzY0MjU1Y3R0MDVoMjVzaGxhNHRweWU3cHhrNSIsIm1uZW1vbmljIjoiY3JhdGVyIG5hbWUgZnJhZ2lsZSBpc2xhbmQgc2tpbGwgY29hc3QgZW50cnkgc291bmQgcmFjZSBvbmNlIGNhcmdvIHN0YWJsZSB3aXNoIG1vb24gdW5jb3ZlciBhbHRlciBhY3Jvc3MgZGlnaXRhbCBkZW1hbmQgc3VpdCBmbG9vciBtZW50aW9uIHB1cGlsIG9seW1waWMifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEzcnpmdHF2d2t0d3E1bW11bXdqNjByNmF3dDVla2Rjc3Fya3V1cCIsIm1uZW1vbmljIjoic3BvbnNvciBsaW1pdCBpbmZsaWN0IGFjaWQgYWxhcm0gZnJlcXVlbnQgYmV0d2VlbiBob21lIHNpbWlsYXIgaW5jb21lIHBlcnNvbiBwYW5kYSBkaWNlIGxhYmVsIG1pc2VyeSBmdWVsIHJvY2tldCBwdWJsaWMga2lzcyB3aWxkIHNpY2sgY3J1Y2lhbCBtYWlsIG11c2ljIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFuZ3Rhbmw0OHN5dHhxNDNjeGpsc3E5cndraHV6bWVzZTc0cWx4ZyIsIm1uZW1vbmljIjoic3BhY2Ugb3Bwb3NlIG9wdGlvbiBibGVzcyBoYW1tZXIgc29sdXRpb24gZW5yaWNoIHZpbGxhZ2UgYmFycmVsIGtuZWUgZ3JhaW4gYXJlYSBzcGVsbCB0cmltIGJ1bGxldCBldmlsIGNvcmUgcmVzY3VlIGJpbmQgYXNwZWN0IG51dCBzaXplIHNwaGVyZSBwYWdlIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEwcnNlazgwbWM1dWVjZmZna3FxNm5xenM3OHNwZndyOHNsOHFwbiIsIm1uZW1vbmljIjoid2lzZG9tIGxlYXZlIGNlaWxpbmcgcmlmbGUgdmlicmFudCBzdGFuZCBwYXRjaCBvbHltcGljIHN3b3JkIHNjYWxlIG1hcmdpbiBzcGlrZSBtZWRhbCBnYXVnZSBicmllZiB2aWNpb3VzIGdvZGRlc3MgYWxtb3N0IGJsb29kIG9yZ2FuIGhhcnNoIGhlYWQgZm9sZCBwcmltYXJ5In0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF6dnF3N2NxZHA1ejQzeHlyOXh2c3pxanJoc3Z1ZjR2dmE4N2VuNiIsIm1uZW1vbmljIjoic3VubnkgZGVjYWRlIGZ1biBiZXN0IGZsZWUgY291Y2ggcHJlc2VudCByZWFkeSBhZ3JlZSBhcmVhIHVuYXdhcmUgcGFycm90IGhvY2tleSB3aGVyZSBzbHVzaCBwZXBwZXIgZmF1bHQgdGhyb3cgdmlzYSBsZW5kIGludG8gZXhoaWJpdCBhbW91bnQgY3J1c2gifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE2cm1nbmVjcjd3N3pldzY3dWtmaHk3eHBjbTk5bXJxbXA2c3NqbCIsIm1uZW1vbmljIjoibmVydmUgZG9vciBtb21lbnQgY2lnYXIgbmVlZCB1c2VmdWwgY29tYmluZSBhZ2UgcmlmbGUgcmV3YXJkIGZyb3plbiBsaXN0IHB1bmNoIHRlbm5pcyBob2xlIGNoYXJnZSBlaWdodCBwZW9wbGUgbGV0dGVyIGNoZWFwIGJ1dHRlciBpbmZvcm0gZmxhbWUgdGVuYW50In0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFybjVhOGdzejMycTl2OHhxMzB4NGc4dnV4dWxnOGNqMmx6dTZqZCIsIm1uZW1vbmljIjoiYXdhcmUgdHVydGxlIHN1biBjYW5ub24gZmFpbnQgaWNlIGhlYXJ0IHdpbGwgY2FrZSB2aWxsYWdlIGZhaW50IGhpcmUgdG93YXJkIHRlYWNoIHBvb2wgYWdlbnQgZ2luZ2VyIGlsbG5lc3MgdG9kYXkgZmV2ZXIgbWlyYWNsZSB3aGVyZSBkZXZlbG9wIHNlYXJjaCJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFqZ2Rja2g0azgyeXV4bjVwZXQyemx5NTV5eHVsN2ttbmx6Z25zcyIsIm1uZW1vbmljIjoiYm94IHRvcnRvaXNlIHNvdXRoIGZldyBkd2FyZiBjb3JhbCBtYWQgd2FsbnV0IHNvbGRpZXIgaHVtYW4gY2FyZ28gY3JhZGxlIGRpc2ggZ2FsYXh5IG5lcnZlIGF3a3dhcmQgZmFudGFzeSBpbm1hdGUga2FuZ2Fyb28gbWVzaCBmYW1lIGN1cnJlbnQgZ3JlYXQgY2FuYWwifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFkZzd2M2hkcDdhN2o5ZGZmZDh1NDBzZ2pmZmM1cXJ3OHU2bmsyYyIsIm1uZW1vbmljIjoiaW5oZXJpdCBwb25kIHB1YmxpYyBtaWxrIGJvZHkgY2hyb25pYyB0dXJ0bGUgZnVuIGRhZCBzdGFuZCBtb2RlbCBob2JieSByaWRnZSBjbHVtcCBtdXN0IGdhdGUgZm94IGxlYXJuIHNhdGlzZnkgc3BhdGlhbCB1cGdyYWRlIGNydWlzZSB3aXNkb20gc2hpcCJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFwNGE1NWU0dnowbHV0eDl0YWFtOTNoNHlmcTl2cjN5aDhwZWF2NiIsIm1uZW1vbmljIjoidHJlbmQgaW5zdGFsbCBtYXNrIGtpdCBydWxlIGtuZWUgdmFyaW91cyBzZXR0bGUgZ2F0aGVyIHNjaXNzb3JzIG9mZmVyIGF3ZnVsIG1haW4gYmlvbG9neSBwdXBpbCBkZXBhcnQgdG9uZ3VlIHdvcmsgYWN0b3IgcmVseSBhbmNpZW50IGRlZnkgYXJ0d29yayBqdWRnZSJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF6OWRsc3loenh2czNhYWFjNXU2a25nd2Y1cnVjcGg0anF2OHFraCIsIm1uZW1vbmljIjoib2JsaWdlIHBocmFzZSBpbmZvcm0gaGlzdG9yeSBlYXNpbHkgYmxvc3NvbSBjb3N0IHRvb3RoIGVhZ2xlIHRydWNrIHNtaWxlIGNydW1ibGUgbWF0cml4IHN3aW5nIG1hcnJpYWdlIG1lcnJ5IHNxdWlycmVsIHBvbGUgcmFjayBzb3VuZCBob3ZlciBoYW5kIHNhdG9zaGkgc3dpbmcifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEzcWw0ejlna2M1anJuYzg4YTlzcXVjejZ5cTJoaDg3aDM3bmc4MyIsIm1uZW1vbmljIjoicHJvcGVydHkgbXlzZWxmIHJlbW92ZSBicm9uemUgYnJhbmQgYW1hemluZyB3YXJtIGhhcmQgdHJpYmUgd2FybSBzY2hlbWUgd2VhciBkZWNsaW5lIHB1cGlsIHJhdGUgYXJ0ZWZhY3QgZHJvcCBlZGdlIGJhbGFuY2UgdG90YWwga2l3aSBxdW90ZSBjaXZpbCBmaWN0aW9uIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF3MGM3NWY1NHNlNnZkcHRhYzV4dHdjMjlqcmxmdHg3MDlrNGgyNSIsIm1uZW1vbmljIjoiY29pbCBzaXJlbiBkaXNvcmRlciB0ZW5hbnQgYWJzZW50IGp1ZGdlIHN1biBnYXJhZ2UgZXZpbCBtb3NxdWl0byBmYXRpZ3VlIGFtYXRldXIgbnVyc2Ugc2Npc3NvcnMgYm9hdCBjYXZlIGNhbnlvbiBwb3dlciB0aGVyZSBtYXJrZXQgc21vb3RoIHZhY2FudCBkZXZpY2UgYWN0In0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFkcmh3eTVscGhyN2c2cTd2Y3dhZ3lsYzc0Y2Fuc2M1dHd3ZDRrdiIsIm1uZW1vbmljIjoiZnJvemVuIGxpcXVpZCBhdm9pZCBmaW5nZXIgcGluayByZWdyZXQgc2hpbmUgbGV2ZWwgd2lkZSBzY2FyZSBtb3RoZXIgc21vb3RoIHNxdWFyZSBzdW5ueSB2aXJ1cyB0b3JjaCBiYW5hbmEgZm9yd2FyZCBpbXBvc2UgY2FuY2VsIGx1bmFyIG51cnNlIGFib3V0IGxheWVyIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE0MzA3eTk0NHBjMzg3NWhlNDU2M3NuejBoNGVmOTJyZzI2Y2syaiIsIm1uZW1vbmljIjoiY29yYWwgcmVqZWN0IGlzb2xhdGUgb3duIHN0b3J5IGJlZ2luIGNyZXcgYmx1ciB0ZW5uaXMgZGlldCBpbnRvIGNhYmxlIHJlcGFpciBleWUgYmV0d2VlbiBjbGltYiBqdWljZSBqYXp6IGdsYXJlIHNxdWVlemUgaGF2ZSB5b3V0aCBtZXNzYWdlIGFuZ3J5In0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF5bjdzM3Z5a3BxN3U5bmtmZGVxcjd4bWNjNDlya3lzOGRqdDJjdCIsIm1uZW1vbmljIjoiYm94IGZhaW50IHRvd24ga25vY2sgYnJpZ2h0IGFueSBhbnRpcXVlIHNsdXNoIGpvaW4gZ29hdCBzcGlyaXQgdHJlYXQgaG9sbG93IHNlY3Rpb24gZ3VpdGFyIHNjaG9vbCB2aXNpdCBzb2FwIG9zdHJpY2ggYmFsbCB0cmVhdCBjb2ZmZWUgZWxkZXIgb3BpbmlvbiJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE4eXQ5eWRlc3R1Nmd3eDJ2NDd6NGprc2ZzdHBjeTkyZGMyeTA2ayIsIm1uZW1vbmljIjoid2luayBmbGF2b3Igb3JiaXQgc2hvb3QgZG9scGhpbiBhZHVsdCBwaWVjZSBjcnVuY2ggYWN0b3IgaW5jaCBuZXJ2ZSByaXR1YWwgZ3JhaW4gYm9zcyB0d28gaG9yc2Ugcm9ja2V0IHdhbnQgcHV6emxlIHR3ZW50eSByZW5ldyBwcmlkZSBzcHJheSBjYWJiYWdlIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFza2cycXd4ZWx2eWFyZmtrZXpjZXh1bXBmcnVoMzRkemhuemdkciIsIm1uZW1vbmljIjoiZm9vZCBuYXN0eSBtYWNoaW5lIGRlcHV0eSBvcmNoYXJkIHJvdXRlIGhlbG1ldCBzdWl0IGVhZ2xlIHdvcmxkIGJyYXZlIGNyYW0gb3pvbmUgd29ybGQgZmFkZSBzaGVkIG1hZCBmb3JnZXQgdG9pbGV0IGFjY2VzcyBldm9rZSBjYXVnaHQgc3RlZWwga2lkbmV5In0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE0YzJrNXlodDB6MmdzdGo1ZWtxZDl4bXJmNXQ1enQ0djA4N25lMiIsIm1uZW1vbmljIjoiYXJvdW5kIHRydWx5IHN3YXAgZ2VuZXJhbCB3b3J0aCBzdWJtaXQgZXhjaGFuZ2UgZHJpdmUgY29tZSBkaW5vc2F1ciBzb3J0IGVsZWN0cmljIGRldGVjdCBwYXNzIHByb2plY3QgZ2lyYWZmZSBjb25maXJtIHNvbmcgc2hyaW1wIGxpYXIgZ3JhYiBhbGllbiByZXdhcmQgdG93biJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFweXd4NnBsbWhldHN0azZmeDZ2czJoaG55emY5dGtyYWh2bDR5aCIsIm1uZW1vbmljIjoiZWxzZSBzYWZlIHBlcHBlciBqb3kgbm9ibGUgaHVtYW4gY2xvY2sgcHJlZGljdCBwb3J0aW9uIHN1ZGRlbiBpbXBvc2UgdGlnZXIgY2FyYm9uIHllYXIgc2xpbSBncmFwZSBwcmV0dHkgZmFpdGggYnVyc3QgbWFzcyBjb3VwbGUgdGVzdCBtYXRoIGZlZWwifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEyeXJrbmNseTBzamo3NjM1NHgyYzllNWNsdGR2aG11bDBzbTAzZSIsIm1uZW1vbmljIjoicmVsYXggb3lzdGVyIGNhdGVnb3J5IGhlbiBhZGRyZXNzIGJveCBzaHJ1ZyBtYW5kYXRlIHdlYXRoZXIgc3BhY2Uga2luZCB0aGF0IGRpYXJ5IHBhZGRsZSBhdXR1bW4gZWRnZSBmYWl0aCB3cm9uZyBmaXggZ293biBzYXZlIG1hc3MgbGVnZW5kIGJ1bGsifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFoc2doejJnam5keWRwejIzc3g5eGxxa2tmZTNwM2xmOGp1NDZudiIsIm1uZW1vbmljIjoiZHVtYiBjYXRhbG9nIHBpc3RvbCBzb2xhciBzcG9vbiBodXJ0IHdhZ2UgYmVsb3cgcHJldmVudCB3aGVhdCBwcm9wZXJ0eSBzcG9uc29yIGNvbmNlcnQgc3lydXAgZ2lmdCByZXBsYWNlIGN1cmlvdXMgYXJyb3cgZmliZXIgYWJzZW50IGF3a3dhcmQgY291c2luIGFkdmljZSBleGNpdGUifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE4MHZqNTk1NDltdHc5aGw1eTZubDc1dTQzMzg3N3Z2OGRlNXFkdyIsIm1uZW1vbmljIjoid2ludGVyIHNwb2lsIG1hc2sgZ3JvdyB3YXZlIHBlcnNvbiB3YWdlIHJveWFsIGdvZGRlc3MgYWNjaWRlbnQgcHJvYmxlbSBjcmF3bCByZWplY3QgZ293biBlbm91Z2ggZmxvb3IgZ2xhbmNlIHJpb3QganVzdCB0b25ndWUgZmFpbnQgdmlydHVhbCBtb2RpZnkgZ2lmdCJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF6YzI1a2UzYXc3dXRlano3dDNqcXRkZHN2bWpza2d6OGpwdW5qdiIsIm1uZW1vbmljIjoiaG9ycm9yIGVhc3QgbWluZCBhY2hpZXZlIG1pZGRsZSBhbmFseXN0IHdyZXN0bGUgbWF4aW11bSBtb3RvciBvc3RyaWNoIHRvZSByb29tIGNsaXAgZXh0cmEgcHJldmVudCBhdWRpdCBjb3VzaW4gY2Fub2UgZGlubmVyIGNoYXQgYWJzZW50IHZlbnVlIHRocml2ZSBuaWdodCJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFheXFtandkM2xhOGE2cTY2NG43YW5ucTdnNDhubTV3Y3J0dnNxMCIsIm1uZW1vbmljIjoidG9wIHNlY3JldCB5b3V0aCBncml0IHN0cm9uZyByYW5jaCBqYXIgZGVsaXZlciBzdHJlZXQgZGVjaWRlIGNvdXBsZSBjcml0aWMgbWl4ZWQgYWxsIHJpb3Qgc2VlZCByZWdpb24gZXRlcm5hbCBhbmNpZW50IGFscGhhIGFtb25nIGh1bnQgbWl4ZWQgYWN0In0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFxcjB3bXdtOHRxN2g2ZHdlcjRoazV1NWU5bnVzeTBtZWFuemUzeSIsIm1uZW1vbmljIjoibWFuc2lvbiBkaWVzZWwgZGlub3NhdXIgbHV4dXJ5IHN1Y2ggb2JzY3VyZSBlbmVyZ3kgcm9va2llIHJpcHBsZSBkZW50aXN0IGF3YXJlIHByZXNlbnQgb3duZXIgY2FjdHVzIGdyYWIgZ2FyZGVuIHByb21vdGUgZ3VpbHQgaHVuZ3J5IHRyYWRlIHN1Z2dlc3QgdmlhYmxlIG5vdmVsIHVuaXZlcnNlIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFqcGE5OTdwZ3EzajBza3V2cHQ0M3VkdXlwNXZod2NwM2ZleTAydCIsIm1uZW1vbmljIjoibW92ZSBzd2FwIG92ZW4gdG9wIG1vbnRoIGV4cGlyZSBob25leSBzdWJtaXQga25pZmUgYXZvY2FkbyB3b29kIG5ldHdvcmsgbWFwbGUgYmx1ciB2b2ljZSBzdWNoIGJyYW5kIGNvY29udXQgYmFubmVyIGVhcm4gbGVvcGFyZCB0dW1ibGUgaG90ZWwgc3Bpcml0In0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF4NWZzajJsbHJ3a2Y4NXFsanBrZTY1eDAybGU1dWp0cWt0M25tNiIsIm1uZW1vbmljIjoiZmV0Y2ggc3RhaXJzIGF2b2NhZG8gbWVtYmVyIHN0dWZmIGFoZWFkIHR1bWJsZSBkaXNtaXNzIHNocnVnIHdhZ29uIGdyYWluIGp1ZGdlIGxlbmd0aCBsb2FkIGN1cnJlbnQgcmFiYml0IG9wZW4gcHJvYmxlbSBlbmZvcmNlIGNvcHkgcGllY2Ugc29sYXIgZXh0cmEgc2tpcnQifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF5ZzgyeTJnd3N2MGM5a201OXFtNjN2bjJ3NGxkcmQ3OXZnN2xjZyIsIm1uZW1vbmljIjoiaWNlIGhpbnQgaG9ybiBsYWJlbCB0aHVuZGVyIHN3YXJtIGNlbGVyeSBzY3JpcHQgZXhlY3V0ZSB2aXRhbCBmZW1hbGUgZ2luZ2VyIGNvcHBlciBmYXRpZ3VlIGxheWVyIGluc3BpcmUgc2lsbHkgZ3Jhdml0eSBtYXRjaCBpdm9yeSBkZXNpZ24gZGFzaCBleGNoYW5nZSBoaXN0b3J5In0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF6ajB3cmcyc2Z6Zzllamp5aHI3emp6bG11em55am1sNmQzZDN3eCIsIm1uZW1vbmljIjoic2NydWIgY291cGxlIGRhbXAgaG9tZSBwYWlyIGNpcmNsZSBiZWF1dHkgZmxvb3Igcm9hZCBzaHkgdHJhZmZpYyBkaWNlIGdyYWluIHRvbW9ycm93IHBlbiBtZWFzdXJlIGxpZmUgY2FycnkgbWlsayBsaXZlIGd1aWx0IHB1c2ggbG9jYWwgY2F0dGxlIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFmYW1uc3hqenZ0Z3VkZmU2cXQ1eHlzc2gzcGY1cjd5cGZodmY5dyIsIm1uZW1vbmljIjoiY2Fubm9uIGJlbmNoIG1vdXNlIHNjYXR0ZXIgZmF0IGhvY2tleSBraXdpIGFzc2F1bHQgZGVjYWRlIG9jY3VyIHJlc291cmNlIHRvZSBhYmlsaXR5IGJlZWYgYmVuY2ggZGFkIHNoaXZlciBlbXBsb3kgdGVhY2ggcmVtYWluIHdlYXBvbiByYXJlIGRpZXQgd2hlZWwifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFoOGNkbjBncGp4cW05MnM4emVybGcydDBleXY0cjB1dzVmMHJ1dCIsIm1uZW1vbmljIjoiY2x1bXAgc2hpZnQgd2VhcG9uIGFjaGlldmUgbnVjbGVhciBuZWNrIHJhdyBnZW51aW5lIHdlZGRpbmcgYm90dG9tIHJpY2ggbmVnbGVjdCBpbnZlc3Qgd2FsayBzb25nIGNoZWYgdW5oYXBweSBwYXVzZSB3aXRuZXNzIGFydCB2YXVsdCByaXR1YWwgZnJpZW5kIGRpZ2l0YWwifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE5eXhqM3AwMjZmcGs0NjBleGwybDJyMnVsZ2czbjdkbnl3czB0OCIsIm1uZW1vbmljIjoiYnVua2VyIG9yZ2FuIGdyb2NlcnkgdHJhbnNmZXIgc2FsdCBlbnRpcmUgYWRtaXQgZ3VhcmQgaWxsZWdhbCBzdGFpcnMga2ljayBjb2x1bW4gZm9yY2UgdmlvbGluIGNsb2NrIGhhbmQgcHVyY2hhc2UgdGFnIGZhdGlndWUgdW52ZWlsIHNpbGx5IGlkZWEgcmF6b3IgZmFuY3kifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE5MnN4enZ5ajYyNXB0ajQ1ZjAydmdlc2x5eG5tYXh3dHlxbmVyOCIsIm1uZW1vbmljIjoiYXJyYW5nZSBzdGVwIGhlYXZ5IG1pc3Rha2UgZmF0aGVyIGJ1bmRsZSBjaGF0IGRlc2NyaWJlIG1hZCBzZXR0bGUgZWFzdCBicmVlemUgdXNlIHdhcnJpb3IgZ3JhcGUgbnVyc2Ugc2F0aXNmeSBuZXN0IHRhcmdldCB2aWNpb3VzIGNvc3QgZ2VudGxlIGVtYm9keSBhbnN3ZXIifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF5NXI3MzhuZnFzNnZseDc2MnM1OGdya3o1dzJycGp2amRoc2ttNCIsIm1uZW1vbmljIjoicmVzaXN0IGVubGlzdCByaW90IHNvbGlkIGxpZnQgZnJvbnQgc3F1ZWV6ZSBhZmZvcmQgbGlxdWlkIGJvbmUgbWF4aW11bSBkb29yIGhhemFyZCBmcmllbmQgcGFkZGxlIHBhZGRsZSBodWIgcmVnaW9uIHNwcmF5IGZpdG5lc3Mgb3JkZXIgdGlzc3VlIGJldHdlZW4gdW5rbm93biJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE0amRmMzM2cmZ1bmVobjZjNDZuemZ6N2YyMzh5NWFsczlnajc3NSIsIm1uZW1vbmljIjoiYWN0b3IgaW50byBtYWtlIHNvbWVvbmUgcGF0aWVudCBjaXZpbCBwbHVuZ2UgYnJhY2tldCB3ZXQgbG92ZSBlbnJpY2ggYW1vdW50IHB1bHAgdmljaW91cyBhd2Vzb21lIGxvZ2ljIG96b25lIHRoYXQgZml0bmVzcyBzaG9wIGJldHdlZW4gZGlub3NhdXIgbGVuZCBsYXRpbiJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFlMm55czk4ejdoa2V4bDJxOWs4eHk5ZzkyejlsbGx2a3gwcHB4cCIsIm1uZW1vbmljIjoiYWNpZCBhbm90aGVyIGF0b20gaW5kb29yIGR5bmFtaWMgdml2aWQgY2hpZWYgbWlsbGlvbiBkeW5hbWljIGJlbGlldmUgdG9kZGxlciByZWxpZWYgYWNoaWV2ZSBhYmlsaXR5IG1lbW9yeSBjb21tb24gc2x1c2ggcmVhc29uIG5vYmxlIG5vYmxlIHF1YWxpdHkgZG92ZSBob2xsb3cgcmVxdWlyZSJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFrdHI3dnc5aDU4ZHo1MDVwazY4cXNjZ2xtdnM5OXVsbmVqZ2ZjOSIsIm1uZW1vbmljIjoiY29uZ3Jlc3MgYnJvY2NvbGkgc3RheSBwZW4gY2hvaWNlIHBhdGNoIHNldmVuIG1hbW1hbCBteXN0ZXJ5IGRpenp5IHdlZWtlbmQgc29sdmUgaW5zYW5lIGN1cCB3YXkgdXNlZnVsIGhvdXIgbGF1Z2ggZ3JvY2VyeSBhbmltYWwgYnJpZ2h0IGZvbGQgY2xpbmljIGRpY2UifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF6bHE5czdtcnZ5c2hhN2g5dHB1MjQwYzYwd3k3MDNyemMzeDJsNiIsIm1uZW1vbmljIjoicmFkYXIgYXJ0aXN0IGZpbGUgcHJvdWQgcGFyZW50IGhhcmJvciBjYXIgdmFyaW91cyBnaG9zdCBtYXJrZXQgbWFycmlhZ2UgZGVtYW5kIHVzdWFsIGFubnVhbCB3aWRlIHNtb2tlIGRpcnQgY3JvdWNoIHNlY3VyaXR5IGljb24gcHJhaXNlIHRvbmlnaHQgcG9ydGlvbiBjYXZlIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFqOXo3dHlhbHprZ3ljZ3ZtaHZmYXIwYWh2eTdhMDJmejcyOXhhdSIsIm1uZW1vbmljIjoieW91IGRpc2Vhc2UgdG9yY2ggY3Jvc3MgdmVyc2lvbiBtb25zdGVyIHNwaWtlIGZldGNoIHBhdGNoIHZpbnRhZ2Ugc2tpbiBmYXZvcml0ZSB3aW5nIGZhY3VsdHkgcmVjaXBlIHF1aXogYWxsb3cgcmlnaWQgcGhvbmUgdGFibGUgaG9ybiBmcmllbmQgd29sZiB2aW9saW4ifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE3MzU1czZ5NzQ0bDgyd3BreDQ5cWxycnQ4amw3dXVoYTkwejcwdiIsIm1uZW1vbmljIjoic2hvb3QgdW5kbyBlbnRpcmUgZmxpcCBvcGVuIGNhdXNlIG9uZSB0b3BpYyByb3VuZCBwdXQgZGV2ZWxvcCBpdGVtIHBvd2RlciBjdXNoaW9uIHdhZ2UgcmV0dXJuIHBpZWNlIGRpdm9yY2Ugc3RlbSBzYXRvc2hpIHByb3NwZXIgc3RhYmxlIHZvY2FsIHNob3ZlIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFmdmh4a2Rsbm50aDRhdnRyOXljeHUwMmpjdHB6czZzZzhhM2w1eCIsIm1uZW1vbmljIjoic2NvcnBpb24gbmFpdmUgZHJlYW0gdGFzayBleGNoYW5nZSBkcnVtIGdyb2NlcnkgZGVncmVlIGhlYXZ5IHByZXBhcmUgZ3JlZW4gYmxvc3NvbSB2ZW51ZSBzeW1wdG9tIGlsbCBwZW9wbGUgbWFqb3IgemVybyBob25leSBvYmxpZ2UgY2VtZW50IG5ldHdvcmsgcmVuZXcgYm9uZSJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE4ZXlyYXpha2F5Nmo1eWhmcHZ4ZDJwdjV4ODBqcHlxOXFrdGZwMiIsIm1uZW1vbmljIjoicm9tYW5jZSBpbmNvbWUgbmV0IHNwbGl0IHJlbmV3IG1pbWljIGpva2UgY29ycmVjdCBhZ2VudCBqb3VybmV5IGxlbnMgYWltIG1vdGhlciBjYWdlIGFzcGVjdCB0cmFwIGJlbGlldmUgdGhyaXZlIGRhbmdlciBtYXRjaCBjcnVtYmxlIGFkdmljZSBhZGRpY3Qgc2NhdHRlciJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF4ZnlodjN2ejZkeW5zMnBneXBtcTRwbDhzMmVyYWFlazB3ZjB1NyIsIm1uZW1vbmljIjoiYnJlZXplIHBldCBwaWFubyBlY2hvIHJpc2sgZGlzbWlzcyBwb2VtIHRoZXkgc2FkbmVzcyBhbWF0ZXVyIG1pbm9yIGNvcHkgcHJpZGUgcXVhcnRlciBhbm90aGVyIGVtZXJnZSBtZWFkb3cgcmV1bmlvbiBleGhhdXN0IHNhbHQgbG9jYWwgbWV0YWwgZGVjYWRlIHZpc2l0In0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE0cHI1N3dnN3gzamw2bmFlODRqd21hbTA2eHBjd2RzdXdjdHF2biIsIm1uZW1vbmljIjoiYW1hdGV1ciBnb2xkIHdvbmRlciB0aXNzdWUgbGVnIHByaWNlIGdsYXJlIGxpbWIgbGl2ZSBmb2lsIGRlc2lnbiByaWdpZCBnb2F0IGNlcnRhaW4gY3Jvd2Qgd2hhbGUga25vY2sgcHJpbnQgcHJldmVudCBzdG9vbCBhdXRvIG1hcmJsZSBnbG9vbSBzY3JpcHQifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF0OHMwODY0Y2V1ZWF6Zjl4bHF5MHh3ajRhOHh0ZWM4cmVkNm1mNSIsIm1uZW1vbmljIjoidG9zcyBjbHViIG1vcm5pbmcgZ3Jhdml0eSBpc29sYXRlIGpvYiBsZWFmIGNsYXkgbGFiIGRyeSBsaWZlIHVudXN1YWwgcHVkZGluZyB2aXZpZCB0YWlsIHBlbGljYW4gdmlzYSBhcnJvdyB3ZWVrZW5kIGtpZG5leSBhbmFseXN0IGFiaWxpdHkgZXF1aXAgbmFycm93In0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFyazN3YWZ5ajZhaDY5eWRsbWtuc2pla3ljdTYwamo5MnRobWFuMiIsIm1uZW1vbmljIjoiZ2x1ZSByb3lhbCB3cmVjayBiZWVmIGFjaWQgdHJpY2sgZ3Vlc3MgYWJzdXJkIGZsYW1lIGNvbW1vbiBjb3JuIGNhc2UgY2hhdCBhdHRpdHVkZSBhZGRyZXNzIHdhbG51dCBleGFtcGxlIHJpZ2lkIGtpd2kgbGVhZGVyIHJpbmcga2lzcyB0ZW50IGRpZXQifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFjc3J1ODg5YXlkcDdhenE4dWo1eGt0a3NwempudmtnbnF3dXY5eiIsIm1uZW1vbmljIjoiZGVicmlzIGZlYnJ1YXJ5IHN0b2NrIGh1bWJsZSBjaGlsZCBndWlsdCBzdGVtIHN0eWxlIHdlZGRpbmcgZnJvZyBkYXVnaHRlciB0b29sIGhvbGxvdyB0ZWFjaCBiaW9sb2d5IGFyb3VuZCBzaWRlIGRlYWwgbG9ic3RlciBjdXJ0YWluIG5lc3QgcXVhbnR1bSBjb21iaW5lIG1pcnJvciJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFhcjVqcGowMzJrYW1oOG40cmRweGR3amhhbXZja2dtejk4d2RtMiIsIm1uZW1vbmljIjoibWVtb3J5IGluanVyeSBvcGVuIG1vbml0b3IgdHVubmVsIGlsbG5lc3MgZGVyaXZlIG9yYW5nZSByZXN1bHQgZGl2ZXJ0IGtpZG5leSBodXJ0IGh1bW9yIGJlY29tZSBhcmd1ZSBidWxiIG1vc3F1aXRvIHRvcHBsZSBiZXN0IGRlY3JlYXNlIHVzdWFsIGxlZ2VuZCBwaXN0b2wgZWl0aGVyIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFjYWZnbDl1d21uemxhbXh3cjZwdHhocGhlNzM5bjVjamgydjQ3bSIsIm1uZW1vbmljIjoic2lnaHQgZGF1Z2h0ZXIgdW5hYmxlIG1vdXNlIGJyaW5nIHNpbGx5IHNldHVwIHZpZXcgYmVlZiBkb3ZlIGx1Z2dhZ2UgYWlycG9ydCBnYW1lIHR3ZW50eSBzaWx2ZXIgZWxkZXIgY2xvZyBtZW50aW9uIGtpdGNoZW4gZ2FyYmFnZSBhaXIgcGF0aWVudCBkZXB0aCBjaG9vc2UifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEzcW52anN2MHN2eWs5Y25sZjBoMGdmbDl4dXY1OW5jc3NmN3ZqdyIsIm1uZW1vbmljIjoiZWxpdGUgc2hpZWxkIHBsYXRlIHB1enpsZSBlZGdlIHNvZnQgY29ycmVjdCBhbmFseXN0IHNhbG9uIGhhcmJvciBzaG92ZSBjdXN0b20gc3VzdGFpbiBsYXVuZHJ5IGthbmdhcm9vIG1vdmllIHdyZWNrIGNsb2cga2lzcyBidXJkZW4gYmluZCBpbmZsaWN0IHVzZWQgYXJlbmEifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEzemRlNTRndTR0cmFzaHdxdHFrbW05N2xuOGVyNmV4enhmbTB1ZiIsIm1uZW1vbmljIjoiZXJyb3IgcXVpdCBmaXggZHVtYiBodXNiYW5kIGNlcmVhbCBzd2ltIGJ1YmJsZSBqdW5pb3IgYnVzaW5lc3MgcmVxdWlyZSBncmFpbiBwdWRkaW5nIG51bWJlciBmYXVsdCB0aGluZyBjZWlsaW5nIGluZmxpY3QgY2hlcnJ5IGN1cmlvdXMgZ2luZ2VyIHJlY29yZCBub3J0aCBnZW5yZSJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFrM3FlcGNseTNueHgzd2psZ2o3ODNobGpldXdqdjVkcjAwNThwdCIsIm1uZW1vbmljIjoiZ2lyYWZmZSBvd24geW91dGggc2hpcCBsZW5zIHNuYXAgcGl0Y2ggcmFpbiB3ZXN0IGV4aGliaXQgYXhpcyBncmFpbiBncml0IHZhbGlkIHZlcmlmeSBzbGFtIHBsdWcgY2FudmFzIHBheW1lbnQgY29zdCBhbG1vc3QgZXhjZXNzIGRlZ3JlZSByYXRlIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE1MDNxNjZzaG16NDZ5NXR1bWN5dW1lbDdyeWw1ZXhycmgzZThyNyIsIm1uZW1vbmljIjoiZm9sZCBnZXN0dXJlIGNvbmdyZXNzIHJhdGUgcGxhc3RpYyBtaW5pbXVtIGhlYWx0aCBzZXR0bGUgY3J5IG9iZXkgbmV2ZXIgc2VyaWVzIGJsYWNrIGtlZW4gc2FpbCBmcm9udCB0eXBlIGZ1cnkgY3J1ZWwgdHJlZSByZW1pbmQgb3JiaXQgdG93YXJkIGZsdWlkIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFrM3R4M3VuMnM4ZXNyams0MDR0cDNuencyYXk1N25kOWN2Z2ZoeSIsIm1uZW1vbmljIjoic2Nob29sIHBlbmNpbCBtdWNoIHRhcmdldCBlbmdpbmUgdXBvbiBzbWFydCB0cnVzdCB3YWdvbiB2ZW50dXJlIG1vZGVsIGFkYXB0IGF0dGVuZCBwdXJwb3NlIGZhY3VsdHkgaHViIHBsdWNrIHZveWFnZSByYWRhciBtaXJyb3IgdmlzaXQgdHJ1bHkgZXhjaGFuZ2UgY2VtZW50In0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE5ejNudWowemZkZ2Z1a3hlYzNsNHNxaGRyZ3kzOG1qdHJscHdhMiIsIm1uZW1vbmljIjoibWVhbiBjbGllbnQgc2NhbGUgY29uc2lkZXIgc291bmQgYmVmb3JlIHJlbWVtYmVyIGVydXB0IHBpdGNoIGljZSBob3JuIGF0dGVuZCBwYXZlIGN1cmlvdXMgcHJlc2VudCBzYWlsIGFpbSByZW1pbmQgdmFsbGV5IGZhdGhlciBzaGlmdCBjYW4gc3RheSBjb29sIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFubXVjYW1hNnVmc2tsdDg2YWNoeG5lZGgzajlkZmd2MmpydmU0NiIsIm1uZW1vbmljIjoidG93biB3aW5kb3cgbG9ic3RlciBwYW5pYyBleGhhdXN0IHByaW9yaXR5IHRpbWUgdmlydHVhbCBjYXJ0IGRyZWFtIHNjb3JwaW9uIHJlcGxhY2Ugb3V0ZXIgd2hlYXQgdW5hYmxlIGFsbGV5IGdhbGxlcnkgc2Npc3NvcnMgY3JldyBnYXRoZXIgbXVjaCBzbGVlcCBhd2FyZSB0YWxrIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEwbTNjdng1ZXA1MHBkeWpscDVlOWVyMnE5NG5oaG01aGc4aHY2cSIsIm1uZW1vbmljIjoicGFsbSBkZXNlcnQgcmVvcGVuIGdpYW50IHRoYXQgb3JwaGFuIHRoZXkgbGVnZW5kIGZyb3N0IHBsdWcgdHdlbnR5IGJvbWIgY3J1bWJsZSBnb3Zlcm4gZW50ZXIgY2FzdGxlIG5lc3QgdGFzdGUgYWJ1c2UgcGVuYWx0eSByYW1wIGltYWdlIHRhYmxlIHRvcHBsZSJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFrbXZubnN2bW0wd2RkcGEyZTd6bDRnYzgwNW0wcTZha2d2cXF6OCIsIm1uZW1vbmljIjoib2JsaWdlIHdhdGVyIHRvcmNoIGZhbnRhc3kgYnJpZWYgZGV0YWlsIHNpbHZlciBibGFjayBicmF2ZSB0YWNrbGUgcG9ueSByaWZsZSBhbHRlciBmZXZlciBsYXZhIGZhaW50IGtub2NrIGluaGFsZSBibHVlIGJlYXV0eSBsaXR0bGUgaGlzdG9yeSBzY2VuZSBlaXRoZXIifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDE2ZDB3N20yZm5oenBsYzl6ZDV2bjJ0OWNkMHc3dDNncng2ODh4MiIsIm1uZW1vbmljIjoibWFuIGNoYXNlIHZlcmIgZGl2b3JjZSByZWN5Y2xlIHRvbWF0byBhcm1lZCBjb3ZlciB3ZWIgd2ludGVyIGRpc21pc3MgZ2xpbXBzZSBwbGFjZSBsaW9uIGNvaW4gY2VyZWFsIGtuZWUgbGluayBwb3dlciBjdXBib2FyZCBmbHVzaCBnbG92ZSBjbHVzdGVyIHN0YWJsZSJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFqdjN1c2R2aDRta2VhM3A4MHk2ZG5ud2RxNWx3bW04dTNsYXB5eCIsIm1uZW1vbmljIjoidHdlbHZlIHBhZ2UgZGF1Z2h0ZXIgY2F0dGxlIHNvcnJ5IGRpc21pc3MgZXhjdXNlIGtpbmQgcmFiYml0IG9wZXJhIHJlcGVhdCBjYW5vZSBndWVzcyB0ZXN0IGNsYXcgZmVicnVhcnkgdm9sY2FubyB0cmFwIHR5cGUgeW91IHJ1cmFsIGNoYWxrIGlubmVyIG5ld3MifQ=="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFlODV2cXJod2tqc2h0ZXZrd3U0cGpnMGFodzczc25lYzl3YWR1aCIsIm1uZW1vbmljIjoiaG9uZXkgYWxidW0gZmVlIGh1bW9yIHNvcnQgdG9tYXRvIHRvZ2V0aGVyIHJpdHVhbCBiZWFuIHdlYXIgcm91Z2ggY3JhZnQgcmV3YXJkIGlzbGFuZCBwdXJjaGFzZSB0ZWxsIHJpdmVyIHJldHVybiBzd2FsbG93IHZvbGNhbm8gc3ByaW5nIHNwZW5kIHdlbGNvbWUgYnVuZGxlIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDEyOHU2OWVucXdjZnF4bWFkZXE3eXhmODZhNjY0aDRxd3k5dHU0OSIsIm1uZW1vbmljIjoicGxhY2UgdHVuYSBuZXJ2ZSBjcmltZSBpbmR1c3RyeSBjb3lvdGUgaGFyZCBjdXNoaW9uIGRpYXJ5IGNoYXQgY29ybiByZW1haW4gc2Vuc2UgbHVnZ2FnZSBsb2NhbCBob3JuIHRpbHQgZm9zdGVyIGluY2ggd2ViIGV4dGVuZCBhbHRlciBkaWxlbW1hIGV4Y2VzcyJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFhcDk2bmowaG1wdXZod25wdXByeGM0Z3hyZ2dsMnN5MzB6YTI4biIsIm1uZW1vbmljIjoidHJ1dGggYmluZCBnYXRoZXIgbG9ic3RlciByb3RhdGUgYmFyZWx5IHZvbHVtZSBoYW1zdGVyIHJpZ2h0IGxlbW9uIHBvbGFyIHZlc3NlbCBtZW1iZXIgY29tZm9ydCBsb2FkIGJyYW5kIG9hayBtaW5pbXVtIHByZWZlciBjcm91Y2ggZ2FkZ2V0IGluZmFudCBjYXV0aW9uIHN0aWxsIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFtOHB1bTJuNXI5dXJsaGZzaHNqc3FlbDB1NzdobGNxcmMyYXJhZiIsIm1uZW1vbmljIjoiZXhwcmVzcyBzY2llbmNlIGV4Y2l0ZSBoYW1tZXIgdGFzayBnb3NwZWwgcmVncmV0IGltcHJvdmUgc3BpZGVyIG5ldCBjYW4gc2VjdGlvbiBzYW1lIGFwcHJvdmUgc2NyZWVuIGlkZWEgYmFsY29ueSBvdmVyIHNlbnRlbmNlIGJpcnRoIGdhbWUgbWFyaW5lIHZveWFnZSBiaW5kIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFwNjc0cnpsOGtsdHhlNjR4MG5rbXF3ZXhnOW13bXpuOWZuc21hciIsIm1uZW1vbmljIjoiYmFieSBidWxsZXQgbWVsb2R5IGNlbnN1cyBoYXJ2ZXN0IHBhY3QgdGF4aSByZWxlYXNlIGNoYW9zIHRyYWRlIHBvZW0gamF6eiBtYWNoaW5lIGNhbnlvbiBibGVhayB0aGFuayBmdXJ5IGFzc2F1bHQgZ2F0ZSBhbnhpZXR5IGxvY2FsIHJvc2UgbW92aWUgd3JhcCJ9"), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF5YWY3c3hsd3Bscmt4MmZ5YW04em0wY3h5ZWF3em1jeDRlanp6OSIsIm1uZW1vbmljIjoic2hlbGwgc2NyYXAgZXJvZGUgbGF3c3VpdCBiYXIgcGFnZSBtZWRhbCBiaXJ0aCBjcnVuY2ggcml0dWFsIGJlbHQgYXNzYXVsdCBzb21lb25lIG5ldHdvcmsgdmF1bHQgY295b3RlIGhvbGxvdyBjYXJyeSBqdW5rIG1hZCBudXQgcG9saWNlIHVuaWZvcm0gY29sdW1uIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDFqd3hua3pkOWY4OTl5ODIybW51aDJ5czQ1MGp5Z2R1bTA1c255YSIsIm1uZW1vbmljIjoiYm9ycm93IHN3ZWFyIGNhdHRsZSByaWRnZSBxdW90ZSBpbXBvc2UgYWJvdmUgbWF0ZXJpYWwgZGVhbCBwb2V0IGFsc28gY2VyZWFsIHR5cGUgdGVubmlzIHJpZGUgZGl2aWRlIGJ1bGsgcGxlZGdlIGdvcmlsbGEgZmF1bHQgY2FycGV0IHZhbiBodXJkbGUgbm9ybWFsIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF2ZTl1bmpjcWV6NnA1dWNwd2tod204YTVhdGZhMmc1N2M0eTA3cyIsIm1uZW1vbmljIjoibWF0cml4IHNraSB3YW50IGNsb3RoIGF0dGFjayBoaWRkZW4gc2FsbW9uIHRyYWRlIGx1eHVyeSBpbml0aWFsIGhhbmQgaG9zcGl0YWwgZmFpbnQgbW90aW9uIHVzZWQgdXNlbGVzcyBjYXZlIHZlcnNpb24gaW5uZXIgcmVtaW5kIGZsaXAgcm9vZiBjb21mb3J0IGxvY2FsIn0="), - mustParsePreGeneratedAccount("eyJhZGRyZXNzIjoicG9rdDF0bWNxY2pucjA1a2w1cHp1NXJkd3h1NncwbmxkanV1YXZ1MHBkcCIsIm1uZW1vbmljIjoic2NoZW1lIGJvdHRvbSBtaWRkbGUgYmVjb21lIGJlc3QgZXNzZW5jZSBwaWdlb24gY29uc2lkZXIgYmFycmVsIHN3YXAgZmF1bHQgc21pbGUgY2FwYWJsZSBoZWFydCBwcm9wZXJ0eSBzaXplIG9mZmljZSB1bmZhaXIgaG9iYnkgbGF0aW4ga2luZ2RvbSBnbGlkZSB0b290aCBjcnVtYmxlIn0="), + 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"), ) ) From eee5dcf58346e6be2cdcd23ddf42b1ce4bd2a144 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 21 Dec 2023 19:37:12 +0100 Subject: [PATCH 17/58] chore: add BaseInMemoryCosmosNetwork abstract impl. --- testutil/network/basenet/accounts.go | 157 +++++++++++++++++++++++++++ testutil/network/basenet/network.go | 106 ++++++++++++++++++ 2 files changed, 263 insertions(+) create mode 100644 testutil/network/basenet/accounts.go create mode 100644 testutil/network/basenet/network.go diff --git a/testutil/network/basenet/accounts.go b/testutil/network/basenet/accounts.go new file mode 100644 index 000000000..740935057 --- /dev/null +++ b/testutil/network/basenet/accounts.go @@ -0,0 +1,157 @@ +package basenet + +import ( + "encoding/json" + "fmt" + "testing" + + "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + testcli "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/poktroll/testutil/network" + "github.com/pokt-network/poktroll/testutil/testkeyring" + apptypes "github.com/pokt-network/poktroll/x/application/types" + gatewaytypes "github.com/pokt-network/poktroll/x/gateway/types" + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" + suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" +) + +const warnNoModuleGenesisFmt = "WARN: no %s module genesis state found, if this is unexpected, ensure that genesis is populated before creating on-chain accounts" + +// CreateKeyringAccounts populates the Keyring associated with the in-memory +// network with memnet.numKeyringAccounts() number of pre-generated accounts. +func (memnet *BaseInMemoryCosmosNetwork) CreateKeyringAccounts(t *testing.T) { + t.Helper() + + if memnet.Config.Keyring == nil { + t.Log("Keyring not initialized, using new in-memory keyring") + + // Construct an in-memory keyring so that it can be populated and used prior + // to network start. + memnet.Config.Keyring = keyring.NewInMemory(memnet.Config.CosmosCfg.Codec) + } else { + t.Log("Keyring already initialized, using existing keyring") + } + + // Create memnet.NumKeyringAccounts() accounts in the configured keyring. + accts := testkeyring.CreatePreGeneratedKeyringAccounts( + t, memnet.Config.Keyring, memnet.Config.GetNumKeyringAccounts(t), + ) + + // Assign the memnet's pre-generated accounts to be a new pre-generated + // accounts iterator containing only the accounts which were also created + // in the keyring. + memnet.PreGeneratedAccounts = testkeyring.NewPreGeneratedAccountIterator(accts...) +} + +func (memnet *BaseInMemoryCosmosNetwork) CreateOnChainAccounts(t *testing.T) { + t.Helper() + + net := memnet.GetNetwork(t) + require.NotEmptyf(t, net, "in-memory cosmos testutil network not initialized yet, call #Start() first") + + supplierGenesisState := network.GetGenesisState[*suppliertypes.GenesisState](t, suppliertypes.ModuleName, memnet) + if supplierGenesisState == nil { + t.Logf(warnNoModuleGenesisFmt, "supplier") + } else { + memnet.InitSupplierAccountsWithSequence(t, supplierGenesisState.SupplierList...) + + } + + appGenesisState := network.GetGenesisState[*apptypes.GenesisState](t, apptypes.ModuleName, memnet) + if appGenesisState == nil { + t.Logf(warnNoModuleGenesisFmt, "application") + } else { + memnet.InitAppAccountsWithSequence(t, appGenesisState.ApplicationList...) + } + + gatewayGenesisState := network.GetGenesisState[*gatewaytypes.GenesisState](t, gatewaytypes.ModuleName, memnet) + if gatewayGenesisState == nil { + t.Logf(warnNoModuleGenesisFmt, "gateway") + } else { + memnet.InitGatewayAccountsWithSequence(t, gatewayGenesisState.GatewayList...) + } + + // need to wait for the account to be initialized in the next block + require.NoError(t, net.WaitForNextBlock()) +} + +// InitAccountWithSequence initializes an Account by sending it some funds from +// the validator in the network to the address provided +func (memnet *BaseInMemoryCosmosNetwork) InitAccountWithSequence( + t *testing.T, + addr types.AccAddress, +) { + t.Helper() + + signerAccountNumber := 0 + // TODO_IN_THIS_COMMIT: comment.. must use validator ctx because its keyring contains the validator key. + clientCtx := memnet.Network.Validators[0].ClientCtx + //clientCtx := memnet.GetClientCtx(t) + net := memnet.GetNetwork(t) + val := net.Validators[0] + + args := []string{ + fmt.Sprintf("--%s=true", flags.FlagOffline), + fmt.Sprintf("--%s=%d", flags.FlagAccountNumber, signerAccountNumber), + fmt.Sprintf("--%s=%d", flags.FlagSequence, memnet.NextAccountSequenceNumber(t)), + + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, types.NewCoins(types.NewCoin(net.Config.BondDenom, math.NewInt(10))).String()), + } + amount := types.NewCoins(types.NewCoin("stake", math.NewInt(200))) + responseRaw, err := testcli.MsgSendExec(clientCtx, val.Address, addr, amount, 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) +} + +func (memnet *BaseInMemoryCosmosNetwork) InitSupplierAccountsWithSequence( + t *testing.T, + supplierList ...sharedtypes.Supplier, +) { + t.Helper() + + net := memnet.GetNetwork(t) + require.NotNil(t, net, "in-memory cosmos testutil network not initialized yet, call #Start() first") + + for _, supplier := range supplierList { + supplierAddr, err := types.AccAddressFromBech32(supplier.GetAddress()) + require.NoError(t, err) + memnet.InitAccountWithSequence(t, supplierAddr) + } +} + +func (memnet *BaseInMemoryCosmosNetwork) InitAppAccountsWithSequence( + t *testing.T, + appList ...apptypes.Application, +) { + t.Helper() + + for _, application := range appList { + appAddr, err := types.AccAddressFromBech32(application.GetAddress()) + require.NoError(t, err) + memnet.InitAccountWithSequence(t, appAddr) + } +} + +func (memnet *BaseInMemoryCosmosNetwork) InitGatewayAccountsWithSequence( + t *testing.T, + gatewayList ...gatewaytypes.Gateway, +) { + t.Helper() + + for _, gateway := range gatewayList { + gatewayAddr, err := types.AccAddressFromBech32(gateway.GetAddress()) + require.NoError(t, err) + memnet.InitAccountWithSequence(t, gatewayAddr) + } +} diff --git a/testutil/network/basenet/network.go b/testutil/network/basenet/network.go new file mode 100644 index 000000000..789c14c24 --- /dev/null +++ b/testutil/network/basenet/network.go @@ -0,0 +1,106 @@ +package basenet + +import ( + "context" + "sync/atomic" + "testing" + + "github.com/cosmos/cosmos-sdk/client" + sdknetwork "github.com/cosmos/cosmos-sdk/testutil/network" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/poktroll/testutil/network" + "github.com/pokt-network/poktroll/testutil/testkeyring" +) + +var _ network.InMemoryCosmosNetwork = (*BaseInMemoryCosmosNetwork)(nil) + +// BaseInMemoryCosmosNetwork is an "abstract" (i.e. partial) implementation, intended +// to be embedded by other ("concrete") InMemoryCosmosNetwork implementations. +type BaseInMemoryCosmosNetwork struct { + Config network.InMemoryNetworkConfig + PreGeneratedAccounts *testkeyring.PreGeneratedAccountIterator + Network *sdknetwork.Network + + lastAccountSeqNumber int32 +} + +// NewBaseInMemoryCosmosNetwork creates a new BaseInMemoryNetwork with the given +// configuration and pre-generated accounts. Intended to be used in constructor +// functions of structs that embed BaseInMemoryCosmosNetwork. +func NewBaseInMemoryCosmosNetwork( + t *testing.T, + cfg *network.InMemoryNetworkConfig, + preGeneratedAccounts *testkeyring.PreGeneratedAccountIterator, +) *BaseInMemoryCosmosNetwork { + t.Helper() + + return &BaseInMemoryCosmosNetwork{ + Config: *cfg, + PreGeneratedAccounts: preGeneratedAccounts, + lastAccountSeqNumber: int32(0), + } +} + +// InitializeDefaults sets the underlying cosmos-sdk testutil network config to +// a reasonable default in case one was not provided with the InMemoryNetworkConfig. +func (memnet *BaseInMemoryCosmosNetwork) InitializeDefaults(t *testing.T) { + if memnet.Config.CosmosCfg == nil { + t.Log("Cosmos config not initialized, using default config") + + // Initialize a network config. + cfg := network.DefaultConfig() + memnet.Config.CosmosCfg = &cfg + } else { + t.Log("Cosmos config already initialized, using existing config") + } +} + +// GetClientCtx returns the underlying cosmos-sdk testutil network's client context. +func (memnet *BaseInMemoryCosmosNetwork) GetClientCtx(t *testing.T) client.Context { + t.Helper() + + require.NotEmptyf(t, memnet.Network, "in-memory network not started yet, call BaseInMemoryCosmosNetwork#Start() first") + + // Only the first validator's client context is populated. + // (see: https://pkg.go.dev/github.com/cosmos/cosmos-sdk/testutil/network#pkg-overview) + ctx := memnet.Network.Validators[0].ClientCtx + + // Overwrite the client context's Keyring with the in-memory one that contains + // our pre-generated accounts. + return ctx.WithKeyring(memnet.Config.Keyring) +} + +// GetNetworkConfig returns the underlying cosmos-sdk testutil network config. +func (memnet *BaseInMemoryCosmosNetwork) GetNetworkConfig(t *testing.T) *sdknetwork.Config { + t.Helper() + + require.NotEmptyf(t, memnet.Config, "in-memory network config not set") + return memnet.Config.CosmosCfg +} + +// GetNetwork returns the underlying cosmos-sdk testutil network instance. +func (memnet *BaseInMemoryCosmosNetwork) GetNetwork(t *testing.T) *sdknetwork.Network { + t.Helper() + + require.NotEmptyf(t, memnet.Network, "in-memory cosmos network not set") + + return memnet.Network +} + +func (memnet *BaseInMemoryCosmosNetwork) GetLastAccountSequenceNumber(t *testing.T) int { + t.Helper() + + return int(memnet.lastAccountSeqNumber) +} + +func (memnet *BaseInMemoryCosmosNetwork) NextAccountSequenceNumber(t *testing.T) int { + t.Helper() + + return int(atomic.AddInt32(&memnet.lastAccountSeqNumber, 1)) +} + +// Start is a stub which is expected to be implemented by embedders. It panics when called. +func (memnet *BaseInMemoryCosmosNetwork) Start(_ context.Context, t *testing.T) { + panic("not implemented") +} From 4af41321397ea548eadbd5624a12f45382a6fc0d Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 21 Dec 2023 19:37:22 +0100 Subject: [PATCH 18/58] feat: add inMemoryNetworkWithSessions impl. --- testutil/network/sessionnet/accounts.go | 136 ++++++++++++++++++++++++ testutil/network/sessionnet/claims.go | 96 +++++++++++++++++ testutil/network/sessionnet/genesis.go | 104 ++++++++++++++++++ testutil/network/sessionnet/network.go | 89 ++++++++++++++++ testutil/network/sessionnet/proofs.go | 86 +++++++++++++++ testutil/network/sessionnet/sessions.go | 108 +++++++++++++++++++ 6 files changed, 619 insertions(+) create mode 100644 testutil/network/sessionnet/accounts.go create mode 100644 testutil/network/sessionnet/claims.go create mode 100644 testutil/network/sessionnet/genesis.go create mode 100644 testutil/network/sessionnet/network.go create mode 100644 testutil/network/sessionnet/proofs.go create mode 100644 testutil/network/sessionnet/sessions.go diff --git a/testutil/network/sessionnet/accounts.go b/testutil/network/sessionnet/accounts.go new file mode 100644 index 000000000..5b44cf86f --- /dev/null +++ b/testutil/network/sessionnet/accounts.go @@ -0,0 +1,136 @@ +package sessionnet + +//import ( +// "encoding/json" +// "fmt" +// "sync/atomic" +// "testing" +// +// "cosmossdk.io/math" +// "github.com/cosmos/cosmos-sdk/client/flags" +// "github.com/cosmos/cosmos-sdk/crypto/keyring" +// testcli "github.com/cosmos/cosmos-sdk/testutil/cli" +// sdknetwork "github.com/cosmos/cosmos-sdk/testutil/network" +// "github.com/cosmos/cosmos-sdk/types" +// "github.com/stretchr/testify/require" +// +// "github.com/pokt-network/poktroll/testutil/network" +// "github.com/pokt-network/poktroll/testutil/testkeyring" +// apptypes "github.com/pokt-network/poktroll/x/application/types" +// sharedtypes "github.com/pokt-network/poktroll/x/shared/types" +// suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" +//) +// +//// createKeyringAccounts populates the Keyring associated with the in-memory +//// network with memnet.numKeyringAccounts() number of pre-generated accounts. +//func (memnet *inMemoryNetworkWithSessions) createKeyringAccounts(t *testing.T) { +// t.Helper() +// +// if memnet.Config.Keyring == nil { +// t.Log("Keyring not initialized, using new in-memory keyring") +// +// // Construct an in-memory keyring so that it can be populated and used prior +// // to network start. +// memnet.Config.Keyring = keyring.NewInMemory(memnet.Config.CosmosCfg.Codec) +// } else { +// t.Log("Keyring already initialized, using existing keyring") +// } +// +// // Create memnet.NumKeyringAccounts() accounts in the configured keyring. +// accts := testkeyring.CreatePreGeneratedKeyringAccounts( +// t, memnet.Config.Keyring, memnet.Config.GetNumKeyringAccounts(t), +// ) +// +// // Assign the memnet's pre-generated accounts to be a new pre-generated +// // accounts iterator containing only the accounts which were also created +// // in the keyring. +// memnet.PreGeneratedAccounts = testkeyring.NewPreGeneratedAccountIterator(accts...) +//} +// +//func (memnet *inMemoryNetworkWithSessions) createOnChainAccounts(t *testing.T) { +// net := memnet.GetNetwork(t) +// supplierGenesisState := network.GetGenesisState[*suppliertypes.GenesisState](t, suppliertypes.ModuleName, memnet) +// appGenesisState := network.GetGenesisState[*apptypes.GenesisState](t, apptypes.ModuleName, memnet) +// +// // Initialize all the accounts +// sequenceIndex := int32(1) +// initSupplierAccountsWithSequence( +// t, net, +// &sequenceIndex, +// supplierGenesisState.SupplierList..., +// ) +// +// initAppAccountsWithSequence( +// t, net, +// &sequenceIndex, +// appGenesisState.ApplicationList..., +// ) +// +// // need to wait for the account to be initialized in the next block +// require.NoError(t, net.WaitForNextBlock()) +//} +// +//// TODO_IN_THIS_COMMIT: integrate with inMemoryNetworkWithSessions? +//func initSupplierAccountsWithSequence( +// t *testing.T, +// net *sdknetwork.Network, +// sequenceIdx *int32, +// supplierList ...sharedtypes.Supplier, +//) { +// t.Helper() +// +// for _, supplier := range supplierList { +// supplierAddr, err := types.AccAddressFromBech32(supplier.GetAddress()) +// require.NoError(t, err) +// InitAccountWithSequence(t, net, supplierAddr, int(*sequenceIdx)) +// atomic.AddInt32(sequenceIdx, 1) +// } +//} +// +//func initAppAccountsWithSequence( +// t *testing.T, +// net *sdknetwork.Network, +// sequenceIdx *int32, +// appList ...apptypes.Application, +//) { +// t.Helper() +// +// for _, application := range appList { +// appAddr, err := types.AccAddressFromBech32(application.GetAddress()) +// require.NoError(t, err) +// InitAccountWithSequence(t, net, appAddr, int(*sequenceIdx)) +// atomic.AddInt32(sequenceIdx, 1) +// } +//} +// +//// InitAccountWithSequence initializes an Account by sending it some funds from +//// the validator in the network to the address provided +//func InitAccountWithSequence( +// t *testing.T, +// net *sdknetwork.Network, +// addr types.AccAddress, +// signatureSequencerNumber int, +//) { +// t.Helper() +// +// val := net.Validators[0] +// signerAccountNumber := 0 +// ctx := val.ClientCtx +// args := []string{ +// fmt.Sprintf("--%s=true", flags.FlagOffline), +// fmt.Sprintf("--%s=%d", flags.FlagAccountNumber, signerAccountNumber), +// fmt.Sprintf("--%s=%d", flags.FlagSequence, signatureSequencerNumber), +// +// fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), +// fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), +// fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), +// fmt.Sprintf("--%s=%s", flags.FlagFees, types.NewCoins(types.NewCoin(net.Config.BondDenom, math.NewInt(10))).String()), +// } +// amount := types.NewCoins(types.NewCoin("stake", math.NewInt(200))) +// responseRaw, err := testcli.MsgSendExec(ctx, val.Address, addr, amount, 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) +//} diff --git a/testutil/network/sessionnet/claims.go b/testutil/network/sessionnet/claims.go new file mode 100644 index 000000000..154034700 --- /dev/null +++ b/testutil/network/sessionnet/claims.go @@ -0,0 +1,96 @@ +package sessionnet + +import ( + "encoding/json" + "fmt" + "testing" + + "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client/flags" + testcli "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/poktroll/pkg/relayer" + "github.com/pokt-network/poktroll/testutil/network" + apptypes "github.com/pokt-network/poktroll/x/application/types" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" + "github.com/pokt-network/poktroll/x/supplier/client/cli" + suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" +) + +// CreateClaims creates a valid claim and corresponding session tree for each +// supplier in the corresponding session for each application's first staked +// service. +func (memnet *inMemoryNetworkWithSessions) CreateClaims( + t *testing.T, +) (claims []suppliertypes.Claim, sessionTrees []relayer.SessionTree) { + // TODO_IN_THIS_COMMIT: update or remove comment. + // Create numSessions * numClaimsPerSession claims for the supplier + for sessionIdx := 0; sessionIdx < memnet.Config.NumSessions; sessionIdx++ { + appGenesisState := network.GetGenesisState[*apptypes.GenesisState](t, apptypes.ModuleName, memnet) + + var lastAppSession *sessiontypes.Session + for _, application := range appGenesisState.ApplicationList { + // TODO_IN_THIS_COMMIT: comment... only using first service as second service has no suppliers staked for it. + serviceId := application.GetServiceConfigs()[0].GetService().GetId() + lastAppSession = memnet.GetSession(t, serviceId, application.GetAddress()) + + for _, supplier := range lastAppSession.GetSuppliers() { + claim, sessionTree := memnet.CreateClaim( + t, supplier.GetAddress(), + lastAppSession.GetHeader(), + ) + claims = append(claims, *claim) + sessionTrees = append(sessionTrees, sessionTree) + + // TODO_TECHDEBT(#196): Move this outside of the forloop so that the test iteration is faster + // TODO_IN_THIS_COMMIT: comment... this screws with the session start height... + require.NoError(t, memnet.GetNetwork(t).WaitForNextBlock()) + } + } + } + return claims, sessionTrees +} + +// CreateClaim sends a tx using the test CLI to create an on-chain claim for the +// given supplier for the given session header. +func (memnet *inMemoryNetworkWithSessions) CreateClaim( + t *testing.T, + supplierAddr string, + sessionHeader *sessiontypes.SessionHeader, +) (*suppliertypes.Claim, relayer.SessionTree) { + t.Helper() + + clientCtx := memnet.GetClientCtx(t) + net := memnet.GetNetwork(t) + + sessionTree := newSessionTreeRoot(t, memnet.Config.NumRelaysPerSession, sessionHeader) + rootHash, rootHashEncoded := getSessionTreeRoot(t, sessionTree) + + sessionHeaderEncoded := cliEncodeSessionHeader(t, sessionHeader) + 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, math.NewInt(10))).String()), + } + + responseRaw, err := testcli.ExecTestCLICmd(clientCtx, 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) + + // TODO_TECHDEBT: Forward the actual claim in the response once the response is updated to return it. + claim := &suppliertypes.Claim{ + SupplierAddress: supplierAddr, + SessionHeader: sessionHeader, + RootHash: rootHash, + } + + return claim, sessionTree +} diff --git a/testutil/network/sessionnet/genesis.go b/testutil/network/sessionnet/genesis.go new file mode 100644 index 000000000..c4b87d927 --- /dev/null +++ b/testutil/network/sessionnet/genesis.go @@ -0,0 +1,104 @@ +package sessionnet + +import ( + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + apptypes "github.com/pokt-network/poktroll/x/application/types" + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" + suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" +) + +// ConfigureDefaultSupplierModuleGenesisState generates and populates the in-memory +// network's application module's GenesisState object with a given number of suppliers, +// each of which is staked for a unique service. It returns the genesis state object. +func (memnet *inMemoryNetworkWithSessions) configureSupplierModuleGenesisState(t *testing.T) *suppliertypes.GenesisState { + t.Helper() + + require.NotEmptyf(t, memnet.GetNetworkConfig(t), "cosmos config not initialized, call #Start() first") + require.NotEmptyf(t, memnet.PreGeneratedAccounts, "pre-generated accounts not initialized, call #Start() first") + + // Create a supplier for each session in numClaimsSessions. + var supplierGenesisState = suppliertypes.DefaultGenesis() + for i := 0; i < memnet.Config.NumSuppliers; i++ { + preGenerateAcct, ok := memnet.PreGeneratedAccounts.Next() + require.True(t, ok) + + supplier := sharedtypes.Supplier{ + Address: preGenerateAcct.Address.String(), + Stake: &sdk.Coin{Denom: "upokt", Amount: sdk.NewInt(10000)}, + Services: []*sharedtypes.SupplierServiceConfig{ + { + Service: &sharedtypes.Service{Id: fmt.Sprintf("svc%d", i)}, + Endpoints: []*sharedtypes.SupplierEndpoint{ + { + Url: "http://localhost:1", + RpcType: sharedtypes.RPCType_JSON_RPC, + }, + }, + }, + }, + } + supplierGenesisState.SupplierList = append(supplierGenesisState.SupplierList, supplier) + } + + supplierGenesisBuffer, err := memnet.GetNetworkConfig(t).Codec.MarshalJSON(supplierGenesisState) + require.NoError(t, err) + + // Add supplier module genesis supplierGenesisState to the network config. + memnet.GetNetworkConfig(t).GenesisState[suppliertypes.ModuleName] = supplierGenesisBuffer + + return supplierGenesisState +} + +// TODO_IN_THIS_COMMIT: draw a diagram of the app/supplier/service session network. + +// ConfigureDefaultApplicationModuleGenesisState generates a GenesisState object +// with a given number of applications which are staked for a service such that +// memnet.Config.AppSupplierPairingRatio*NumSuppliers number of applications are +// staked for each supplier's service (assumes that each supplier is staked for +// a unique service with no overlap). +func (memnet *inMemoryNetworkWithSessions) configureAppModuleGenesisState(t *testing.T) *apptypes.GenesisState { + t.Helper() + + require.NotEmptyf(t, memnet.GetNetworkConfig(t), "cosmos config not initialized, call #Start() first") + require.NotEmptyf(t, memnet.PreGeneratedAccounts, "pre-generated accounts not initialized, call #Start() first") + + var ( + serviceIdx = 0 + appGenesisState = apptypes.DefaultGenesis() + ) + for i := 0; i < memnet.Config.GetNumApplications(t); i++ { + preGeneratedAcct, ok := memnet.PreGeneratedAccounts.Next() + require.True(t, ok) + + application := apptypes.Application{ + Address: preGeneratedAcct.Address.String(), + Stake: &sdk.Coin{Denom: "upokt", Amount: sdk.NewInt(10000)}, + ServiceConfigs: []*sharedtypes.ApplicationServiceConfig{ + {Service: &sharedtypes.Service{Id: fmt.Sprintf("svc%d", serviceIdx)}}, + // NB: applications are staked for a service which no supplier is staked for. + {Service: &sharedtypes.Service{Id: fmt.Sprintf("nosvc%d", serviceIdx)}}, + }, + } + appGenesisState.ApplicationList = append(appGenesisState.ApplicationList, application) + + // NB: only increment serviceIdx every AppSupplierPairingRatio applications + // to ensure that AppSupplierPairingRatio*NumSuppliers number of applications + // are staked for each supplier's service (ea. supplier is currently staked + // for a unique service with no overlap). + if (i+1)%memnet.Config.AppSupplierPairingRatio == 0 { + serviceIdx++ + } + } + appGenesisBuffer, err := memnet.Config.CosmosCfg.Codec.MarshalJSON(appGenesisState) + require.NoError(t, err) + + // Add supplier and application module genesis appGenesisState to the network memnetConfig. + memnet.GetNetworkConfig(t).GenesisState[apptypes.ModuleName] = appGenesisBuffer + + return appGenesisState +} diff --git a/testutil/network/sessionnet/network.go b/testutil/network/sessionnet/network.go new file mode 100644 index 000000000..364c799ff --- /dev/null +++ b/testutil/network/sessionnet/network.go @@ -0,0 +1,89 @@ +package sessionnet + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/pokt-network/poktroll/testutil/network" + "github.com/pokt-network/poktroll/testutil/network/basenet" + "github.com/pokt-network/poktroll/testutil/testkeyring" +) + +var _ network.InMemoryCosmosNetwork = (*inMemoryNetworkWithSessions)(nil) + +// inMemoryNetworkWithSessions is an implementation of the InMemoryCosmosNetwork interface. +type inMemoryNetworkWithSessions struct { + basenet.BaseInMemoryCosmosNetwork +} + +// TODO_IN_THIS_COMMIT: consider renaming & consolidating in network/types.go +// +// DefaultInMemoryNetworkConfig returns the default in-memory network configuration. +// This configuration should sufficient populate on-chain objects to support reasonable +// coverage around most session-oriented scenarios. +func DefaultInMemoryNetworkConfig(t *testing.T) *network.InMemoryNetworkConfig { + t.Helper() + + return &network.InMemoryNetworkConfig{ + NumSessions: 4, + NumRelaysPerSession: 5, + NumBlocksPerSession: 5, + NumSuppliers: 2, + AppSupplierPairingRatio: 2, + } +} + +// DefaultNetworkWithSessions creates a new in-memory network using the default configuration. +func DefaultNetworkWithSessions(t *testing.T) *inMemoryNetworkWithSessions { + t.Helper() + + return NewInMemoryNetworkWithSessions(t, DefaultInMemoryNetworkConfig(t)) +} + +// NewInMemoryNetworkWithSessions creates a new in-memory network with the given configuration. +func NewInMemoryNetworkWithSessions(t *testing.T, cfg *network.InMemoryNetworkConfig) *inMemoryNetworkWithSessions { + t.Helper() + + return &inMemoryNetworkWithSessions{ + BaseInMemoryCosmosNetwork: basenet.BaseInMemoryCosmosNetwork{ + Config: *cfg, + PreGeneratedAccounts: testkeyring.NewPreGeneratedAccountIterator(), + }, + } +} + +// Start initializes the in-memory network and performs the following setup: +// - populates a new in-memory keyring with a sufficient number of pre-generated accounts. +// - configures the application module's genesis state using addresses corresponding +// to config.NumApplications number of the same pre-generated accounts which were +// added to the keyring. +// - configures the supplier module's genesis state using addresses corresponding to +// config.NumSuppliers number of the same pre-generated accounts which were added +// to the keyring. +// - creates the on-chain accounts in the accounts module which correspond to the +// pre-generated accounts which were added to the keyring. +func (memnet *inMemoryNetworkWithSessions) Start(_ context.Context, t *testing.T) { + t.Helper() + + // Application module genesis state fixture data is generated in terms of + // AppToSupplierRatio, and NumApplications cannot encode the distribution + // of the application/supplier pairings. + if memnet.Config.NumApplications > 0 { + panic("NumApplications must be 0 for inMemoryNetworkWithSession, use AppToSupplierRatio instead") + } + + memnet.InitializeDefaults(t) + memnet.CreateKeyringAccounts(t) + + // Configure supplier and application module genesis states. + memnet.configureAppModuleGenesisState(t) + memnet.configureSupplierModuleGenesisState(t) + + memnet.Network = network.New(t, *memnet.GetNetworkConfig(t)) + err := memnet.Network.WaitForNextBlock() + require.NoError(t, err) + + memnet.CreateOnChainAccounts(t) +} diff --git a/testutil/network/sessionnet/proofs.go b/testutil/network/sessionnet/proofs.go new file mode 100644 index 000000000..26c9f2a9a --- /dev/null +++ b/testutil/network/sessionnet/proofs.go @@ -0,0 +1,86 @@ +package sessionnet + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "testing" + + "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client/flags" + testcli "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/poktroll/pkg/relayer" + "github.com/pokt-network/poktroll/testutil/network" + "github.com/pokt-network/poktroll/x/supplier/client/cli" + "github.com/pokt-network/poktroll/x/supplier/types" +) + +// SubmitProofs generates and submits a proof for each claim in the provided +// list of claims. Claims are paired with session trees by index but is otherwise +// arbitrary (any session tree could be used for any claim). +func (memnet *inMemoryNetworkWithSessions) SubmitProofs( + t *testing.T, + claims []types.Claim, + sessionTrees []relayer.SessionTree, +) []types.Proof { + t.Helper() + require.Equal(t, len(claims), len(sessionTrees), "number of claims and session trees must be equal") + + var proofs []types.Proof + for i, claim := range claims { + proof := memnet.SubmitProof(t, claim, sessionTrees[i]) + proofs = append(proofs, *proof) + + // TODO_TECHDEBT(#196): Move this outside of the forloop so that the test iteration is faster + net := memnet.GetNetwork(t) + require.NoError(t, net.WaitForNextBlock()) + } + return proofs +} + +// SubmitProof generates and submits a proof for the given claim and session tree. +func (memnet *inMemoryNetworkWithSessions) SubmitProof( + t *testing.T, + claim types.Claim, + sessionTree relayer.SessionTree, +) *types.Proof { + t.Helper() + + merkelProof, err := sessionTree.ProveClosest(network.TestProofPath) + require.NoError(t, err) + + proofBz, err := merkelProof.Marshal() + require.NoError(t, err) + + sessionHeaderEncoded := cliEncodeSessionHeader(t, claim.GetSessionHeader()) + proofEncoded := base64.StdEncoding.EncodeToString(proofBz) + + bondDenom := memnet.GetNetwork(t).Config.BondDenom + args := []string{ + sessionHeaderEncoded, + proofEncoded, + fmt.Sprintf("--%s=%s", flags.FlagFrom, claim.GetSupplierAddress()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(bondDenom, math.NewInt(10))).String()), + } + + ctx := memnet.GetClientCtx(t) + responseRaw, err := testcli.ExecTestCLICmd(ctx, cli.CmdSubmitProof(), 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) + + proof := &types.Proof{ + SupplierAddress: claim.GetSupplierAddress(), + SessionHeader: claim.GetSessionHeader(), + MerkleProof: proofBz, + } + + return proof +} diff --git a/testutil/network/sessionnet/sessions.go b/testutil/network/sessionnet/sessions.go new file mode 100644 index 000000000..b8a92c8a2 --- /dev/null +++ b/testutil/network/sessionnet/sessions.go @@ -0,0 +1,108 @@ +package sessionnet + +import ( + "context" + "encoding/base64" + "os" + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/poktroll/pkg/relayer" + "github.com/pokt-network/poktroll/pkg/relayer/session" + "github.com/pokt-network/poktroll/testutil/testrelayer" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" +) + +// GetSession sends a query using the test CLI to get a session for the inputs provided. +func (memnet *inMemoryNetworkWithSessions) GetSession( + t *testing.T, + serviceId string, + appAddr string, +) *sessiontypes.Session { + t.Helper() + ctx := context.TODO() + net := memnet.GetNetwork(t) + + sessionQueryClient := sessiontypes.NewQueryClient(net.Validators[0].ClientCtx) + res, err := sessionQueryClient.GetSession(ctx, &sessiontypes.QueryGetSessionRequest{ + ApplicationAddress: appAddr, + Service: &sharedtypes.Service{Id: serviceId}, + // NB(#196): intentionally omitting BlockHeight (i.e. session start height) + // as it is difficult to predict in the general case. + // BlockHeight: + }) + require.NoError(t, err) + + return res.GetSession() +} + +// cliEncodeSessionHeader encodes the given session header as a base64-encoded +// string. +func cliEncodeSessionHeader(t *testing.T, sessionHeader *sessiontypes.SessionHeader) string { + t.Helper() + + cdc := codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) + sessionHeaderBz := cdc.MustMarshalJSON(sessionHeader) + return base64.StdEncoding.EncodeToString(sessionHeaderBz) +} + +// newSessionTreeRoot creates and returns a new session tree with the given number +// of relays and session header. All SMT persistence is done in a temporary and +// is cleaned up when the test completes. +func newSessionTreeRoot( + t *testing.T, + numRelays int, + sessionHeader *sessiontypes.SessionHeader, +) relayer.SessionTree { + t.Helper() + + tmpSmtStorePath, err := os.MkdirTemp("", t.Name()) + require.NoError(t, err) + + // Ensure all persisted trees are removed after the test completes. + t.Cleanup(func() { + if err = os.RemoveAll(tmpSmtStorePath); err != nil { + t.Logf("WARNING: failed to delete temporary SMT store path %s: %s", tmpSmtStorePath, err) + } + }) + + // This function is a required constructor argument but is only called at the + // end of `sessionTree#Delete()`, which this test doesn't exercise. + noop := func(header *sessiontypes.SessionHeader) {} + sessionTree, err := session.NewSessionTree(sessionHeader, tmpSmtStorePath, noop) + require.NoError(t, err) + + for i := 0; i < numRelays; i++ { + // While these relays use the `MinedRelay` data structure, they are not + // "mined" in the sense that their inclusion is dependent on their difficulty. + // `MinedRelay` fixtures produced this way effectively have difficulty 0. + relay := testrelayer.NewMinedRelay( + t, sessionHeader.GetSessionStartBlockHeight(), + sessionHeader.GetSessionEndBlockHeight(), + ) + + err := sessionTree.Update(relay.Hash, relay.Bytes, 1) + require.NoError(t, err) + + } + return sessionTree +} + +// getSessionTreeRoot returns the root hash of the given sessionTree as a both a +// byte slice and a base64-encoded string. +func getSessionTreeRoot( + t *testing.T, + sessionTree relayer.SessionTree, +) ([]byte, string) { + t.Helper() + + rootHashBz, err := sessionTree.Flush() + require.NoError(t, err) + + rootHashEncoded := base64.StdEncoding.EncodeToString(rootHashBz) + return rootHashBz, rootHashEncoded +} From ae7de37b24f854eeea2a9a3b552e60e8981ab255 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 21 Dec 2023 19:37:31 +0100 Subject: [PATCH 19/58] feat: add inMemoryNetworkWithGateways --- testutil/network/gatewaynet/network.go | 190 +++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 testutil/network/gatewaynet/network.go diff --git a/testutil/network/gatewaynet/network.go b/testutil/network/gatewaynet/network.go new file mode 100644 index 000000000..5b24e2816 --- /dev/null +++ b/testutil/network/gatewaynet/network.go @@ -0,0 +1,190 @@ +package gatewaynet + +import ( + "context" + "fmt" + "testing" + + "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client/flags" + testcli "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/poktroll/testutil/network" + "github.com/pokt-network/poktroll/testutil/network/basenet" + "github.com/pokt-network/poktroll/testutil/testkeyring" + "github.com/pokt-network/poktroll/x/application/client/cli" + apptypes "github.com/pokt-network/poktroll/x/application/types" + gatewaytypes "github.com/pokt-network/poktroll/x/gateway/types" + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" +) + +var _ network.InMemoryCosmosNetwork = (*inMemoryNetworkWithGateways)(nil) + +// inMemoryNetworkWithGateways is an implementation of the InMemoryCosmosNetwork interface. +type inMemoryNetworkWithGateways struct { + //baseInMemoryNetwork basenet.BaseInMemoryCosmosNetwork + basenet.BaseInMemoryCosmosNetwork +} + +// DefaultInMemoryNetworkConfig returns the default in-memory network configuration. +// This configuration should sufficient populate on-chain objects to support reasonable +// coverage around most session-oriented scenarios. +func DefaultInMemoryNetworkConfig(t *testing.T) *network.InMemoryNetworkConfig { + t.Helper() + + return &network.InMemoryNetworkConfig{ + NumGateways: 5, + NumSuppliers: 2, + AppSupplierPairingRatio: 1, + } +} + +// NewInMemoryNetworkWithGateways creates a new in-memory network with the given configuration. +func NewInMemoryNetworkWithGateways(t *testing.T, cfg *network.InMemoryNetworkConfig) *inMemoryNetworkWithGateways { + t.Helper() + + return &inMemoryNetworkWithGateways{ + BaseInMemoryCosmosNetwork: *basenet.NewBaseInMemoryCosmosNetwork( + t, cfg, testkeyring.NewPreGeneratedAccountIterator(), + ), + } +} + +func (memnet *inMemoryNetworkWithGateways) DelegateAppToGateway( + t *testing.T, + appBech32 string, + gatewayBech32 string, +) { + t.Helper() + + args := []string{ + gatewayBech32, + fmt.Sprintf("--%s=%s", flags.FlagFrom, appBech32), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(memnet.GetNetwork(t).Config.BondDenom, math.NewInt(10))).String()), + } + responseRaw, err := testcli.ExecTestCLICmd(memnet.GetClientCtx(t), cli.CmdDelegateToGateway(), args) + require.NoError(t, err) + var resp sdk.TxResponse + require.NoError(t, memnet.GetNetworkConfig(t).Codec.UnmarshalJSON(responseRaw.Bytes(), &resp)) + require.NotNil(t, resp) + require.NotNil(t, resp.TxHash) + require.Equal(t, uint32(0), resp.Code) +} + +func (memnet *inMemoryNetworkWithGateways) UndelegateAppFromGateway( + t *testing.T, + appBech32 string, + gatewayBech32 string, +) { + + args := []string{ + gatewayBech32, + fmt.Sprintf("--%s=%s", flags.FlagFrom, appBech32), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(memnet.GetNetworkConfig(t).BondDenom, math.NewInt(10))).String()), + } + responseRaw, err := testcli.ExecTestCLICmd(memnet.GetClientCtx(t), cli.CmdUndelegateFromGateway(), args) + require.NoError(t, err) + var resp sdk.TxResponse + require.NoError(t, memnet.GetNetworkConfig(t).Codec.UnmarshalJSON(responseRaw.Bytes(), &resp)) + require.NotNil(t, resp) + require.NotNil(t, resp.TxHash) + require.Equal(t, uint32(0), resp.Code) +} + +// TODO_IN_THIS_COMMIT: update comment +// +// Start initializes the in-memory network and performs the following setup: +// - populates a new in-memory keyring with a sufficient number of pre-generated accounts. +// - configures the application module's genesis state using addresses corresponding +// to config.NumApplications number of the same pre-generated accounts which were +// added to the keyring. +// - configures the supplier module's genesis state using addresses corresponding to +// config.NumSuppliers number of the same pre-generated accounts which were added +// to the keyring. +// - creates the on-chain accounts in the accounts module which correspond to the +// pre-generated accounts which were added to the keyring. +func (memnet *inMemoryNetworkWithGateways) Start(_ context.Context, t *testing.T) { + t.Helper() + + // Application module genesis state fixture data generation is independent + // of that of the supplier module. + if memnet.Config.AppSupplierPairingRatio > 0 { + panic("AppSupplierPairingRatio must be 0 for inMemoryNetworkWithGateways, use NumApplications instead") + } + + memnet.InitializeDefaults(t) + memnet.CreateKeyringAccounts(t) + + // Configure gateway and application module genesis states. + memnet.configureGatewayModuleGenesisState(t) + memnet.configureAppModuleGenesisState(t) + + memnet.Network = network.New(t, *memnet.GetNetworkConfig(t)) + + memnet.CreateOnChainAccounts(t) +} + +// TODO_IN_THIS_COMMIT: fix comment... +// GatewayModuleGenesisStateWithAddresses generates a GenesisState object with +// a gateway list full of gateways with the given addresses. +func (memnet *inMemoryNetworkWithGateways) configureGatewayModuleGenesisState(t *testing.T) { + t.Helper() + + gatewayGenesisState := gatewaytypes.DefaultGenesis() + for gatewayIdx := 0; gatewayIdx < memnet.Config.NumGateways; gatewayIdx++ { + stake := sdk.NewCoin("upokt", sdk.NewInt(int64(gatewayIdx))) + preGeneratedAcct, ok := memnet.PreGeneratedAccounts.Next() + require.Truef(t, ok, "pre-generated accounts iterator exhausted") + require.Truef(t, ok, "pre-generated accounts iterator exhausted") + + gateway := gatewaytypes.Gateway{ + Address: preGeneratedAcct.Address.String(), + Stake: &stake, + } + + // TODO_CONSIDERATION: Evaluate whether we need `nullify.Fill` or if we should enforce `(gogoproto.nullable) = false` everywhere + // nullify.Fill(&gateway) + gatewayGenesisState.GatewayList = append(gatewayGenesisState.GatewayList, gateway) + } + + gatewayGenesisBuffer, err := memnet.GetNetworkConfig(t).Codec.MarshalJSON(gatewayGenesisState) + require.NoError(t, err) + + // Add supplier module genesis supplierGenesisState to the network config. + memnet.GetNetworkConfig(t).GenesisState[gatewaytypes.ModuleName] = gatewayGenesisBuffer +} + +func (memnet *inMemoryNetworkWithGateways) configureAppModuleGenesisState(t *testing.T) { + t.Helper() + + require.NotEmptyf(t, memnet.GetNetworkConfig(t), "cosmos config not initialized, call #Start() first") + require.NotEmptyf(t, memnet.PreGeneratedAccounts, "pre-generated accounts not initialized, call #Start() first") + + var appGenesisState = apptypes.DefaultGenesis() + for appIdx := 0; appIdx < memnet.Config.GetNumApplications(t); appIdx++ { + preGeneratedAcct, ok := memnet.PreGeneratedAccounts.Next() + require.Truef(t, ok, "pre-generated accounts iterator exhausted") + + application := apptypes.Application{ + Address: preGeneratedAcct.Address.String(), + Stake: &sdk.Coin{Denom: "upokt", Amount: sdk.NewInt(10000)}, + ServiceConfigs: []*sharedtypes.ApplicationServiceConfig{ + {Service: &sharedtypes.Service{Id: fmt.Sprintf("svc%d", appIdx)}}, + // NB: applications are staked for a service which no supplier is staked for. + {Service: &sharedtypes.Service{Id: fmt.Sprintf("nosvc%d", appIdx)}}, + }, + } + appGenesisState.ApplicationList = append(appGenesisState.ApplicationList, application) + } + appGenesisBuffer, err := memnet.Config.CosmosCfg.Codec.MarshalJSON(appGenesisState) + require.NoError(t, err) + + // Add supplier and application module genesis appGenesisState to the network memnetConfig. + memnet.GetNetworkConfig(t).GenesisState[apptypes.ModuleName] = appGenesisBuffer +} From a2e53c1bd400b748e98ac321d92401c0510fbc4f Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 21 Dec 2023 21:36:00 +0100 Subject: [PATCH 20/58] chore: add GetGenesis test helper --- testutil/network/genesis.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 testutil/network/genesis.go diff --git a/testutil/network/genesis.go b/testutil/network/genesis.go new file mode 100644 index 000000000..05eede88e --- /dev/null +++ b/testutil/network/genesis.go @@ -0,0 +1,30 @@ +package network + +import ( + "reflect" + "testing" + + "github.com/cosmos/gogoproto/proto" + "github.com/stretchr/testify/require" +) + +// GetGenesisState retrieves the genesis state for a given module from the +// underlying cosmos-sdk testutil network. +func GetGenesisState[T proto.Message](t *testing.T, moduleName string, memnet InMemoryCosmosNetwork) T { + t.Helper() + + require.NotEmptyf(t, memnet.GetNetwork(t), "in-memory network not started yet, call inMemoryNetworkWithSessions#Start() first") + + var genesisState T + // NB: As this function is generic, it MUST use reflect in order to unmarshal + // the genesis state as the codec requries a reference to a concrete type pointer. + genesisStateType := reflect.TypeOf(genesisState) + genesisStateValue := reflect.New(genesisStateType.Elem()) + genesisStatePtr := genesisStateValue.Interface().(proto.Message) + + genesisStateJSON := memnet.GetNetworkConfig(t).GenesisState[moduleName] + err := memnet.GetNetworkConfig(t).Codec.UnmarshalJSON(genesisStateJSON, genesisStatePtr) + require.NoError(t, err) + + return genesisStatePtr.(T) +} From 93125b04bf75f342932e45e0024fa73c97757eba Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 22 Dec 2023 16:18:15 +0100 Subject: [PATCH 21/58] chore: add godoc comments & simplify --- testutil/network/types.go | 55 +++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/testutil/network/types.go b/testutil/network/types.go index 716942c56..ea40fe1d7 100644 --- a/testutil/network/types.go +++ b/testutil/network/types.go @@ -5,19 +5,52 @@ import ( "github.com/cosmos/cosmos-sdk/testutil/network" ) -// TODO_IN_THIS_COMMIT: godocs comment... -var TestProofPath = []byte("test_proof_path") +// TestMerkleProofPath is intended to be used as a "path" in a merkle tree for +// which to generate a proof. +var TestMerkleProofPath = []byte("test_proof_merkle_path") -// TODO_IN_THIS_COMMIT: godocs comments... +// InMemoryNetworkConfig is a **SHARED** config struct for use by InMemoryCosmosNetwork +// implementations to configure themselves, provide the necessary parameters to set-up +// code, and initialize the underlying cosmos-sdk testutil network. +// +// Examples of set-up operations include but are not limited to: +// - Creating accounts in the local keyring. +// - Creating genesis state for (a) module(s). +// - Executing on-chain transactions (i.e. on-chain, non-genesis state). type InMemoryNetworkConfig struct { - NumSessions int + // NumSessions is the number of sessions (with sequential start heights) for + // which the network should generate claims and proofs. + NumSessions int + + // NumRelaysPerSession is the number of nodes to be inserted into each claim's + // session tree prior to generating the corresponding proof. NumRelaysPerSession int - NumBlocksPerSession int - NumSuppliers int - NumGateways int - NumApplications int - // TODO_IN_THIS_COMMIT: comment ... w/ the **same serviceId**... mutually exclusive w/ NumApplications + + // NumSuppliers is the number of suppliers that should be created at genesis. + NumSuppliers int + + // NumGateways is the number of gateways that should be created at genesis. + NumGateways int + + // NumApplications is the number of applications that should be created at genesis. + // Usage is mutually exclusive with AppSupplierPairingRatio. This is enforced by + // InMemoryCosmosNetwork implementations. + NumApplications int + + // AppSupplierPairingRatio is the number of applications, per supplier, that + // share a serviceId (i.e. will be in the same session). + // Usage is mutually exclusive with NumApplications. This is enforced by + // InMemoryCosmosNetwork implementations. AppSupplierPairingRatio int - CosmosCfg *network.Config - Keyring keyring.Keyring + + // CosmosCfg is the configuration for the underlying cosmos-sdk testutil network. + CosmosCfg *network.Config + + // Keyring is the keyring to be used by clients of the cosmos-sdk testutil network. + // It is intended to be populated with a sufficient number of accounts for the + // InMemoryCosmosNetwork implementation's use cases. BaseInMemoryCosmosNetwork + // implements a #GetNumKeyringAccounts() for this purpose. + // This keyring is associated with the cosmos client context returned from + // BaseInMemoryCosmosNetwork#GetClientCtx(). + Keyring keyring.Keyring } From 6737cb786bcc86bd04775daa128cafae4602a0f4 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 22 Dec 2023 17:04:11 +0100 Subject: [PATCH 22/58] fixup! feat: add inMemoryNetworkWithSessions impl. --- testutil/network/sessionnet/accounts.go | 136 ------------------------ 1 file changed, 136 deletions(-) delete mode 100644 testutil/network/sessionnet/accounts.go diff --git a/testutil/network/sessionnet/accounts.go b/testutil/network/sessionnet/accounts.go deleted file mode 100644 index 5b44cf86f..000000000 --- a/testutil/network/sessionnet/accounts.go +++ /dev/null @@ -1,136 +0,0 @@ -package sessionnet - -//import ( -// "encoding/json" -// "fmt" -// "sync/atomic" -// "testing" -// -// "cosmossdk.io/math" -// "github.com/cosmos/cosmos-sdk/client/flags" -// "github.com/cosmos/cosmos-sdk/crypto/keyring" -// testcli "github.com/cosmos/cosmos-sdk/testutil/cli" -// sdknetwork "github.com/cosmos/cosmos-sdk/testutil/network" -// "github.com/cosmos/cosmos-sdk/types" -// "github.com/stretchr/testify/require" -// -// "github.com/pokt-network/poktroll/testutil/network" -// "github.com/pokt-network/poktroll/testutil/testkeyring" -// apptypes "github.com/pokt-network/poktroll/x/application/types" -// sharedtypes "github.com/pokt-network/poktroll/x/shared/types" -// suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" -//) -// -//// createKeyringAccounts populates the Keyring associated with the in-memory -//// network with memnet.numKeyringAccounts() number of pre-generated accounts. -//func (memnet *inMemoryNetworkWithSessions) createKeyringAccounts(t *testing.T) { -// t.Helper() -// -// if memnet.Config.Keyring == nil { -// t.Log("Keyring not initialized, using new in-memory keyring") -// -// // Construct an in-memory keyring so that it can be populated and used prior -// // to network start. -// memnet.Config.Keyring = keyring.NewInMemory(memnet.Config.CosmosCfg.Codec) -// } else { -// t.Log("Keyring already initialized, using existing keyring") -// } -// -// // Create memnet.NumKeyringAccounts() accounts in the configured keyring. -// accts := testkeyring.CreatePreGeneratedKeyringAccounts( -// t, memnet.Config.Keyring, memnet.Config.GetNumKeyringAccounts(t), -// ) -// -// // Assign the memnet's pre-generated accounts to be a new pre-generated -// // accounts iterator containing only the accounts which were also created -// // in the keyring. -// memnet.PreGeneratedAccounts = testkeyring.NewPreGeneratedAccountIterator(accts...) -//} -// -//func (memnet *inMemoryNetworkWithSessions) createOnChainAccounts(t *testing.T) { -// net := memnet.GetNetwork(t) -// supplierGenesisState := network.GetGenesisState[*suppliertypes.GenesisState](t, suppliertypes.ModuleName, memnet) -// appGenesisState := network.GetGenesisState[*apptypes.GenesisState](t, apptypes.ModuleName, memnet) -// -// // Initialize all the accounts -// sequenceIndex := int32(1) -// initSupplierAccountsWithSequence( -// t, net, -// &sequenceIndex, -// supplierGenesisState.SupplierList..., -// ) -// -// initAppAccountsWithSequence( -// t, net, -// &sequenceIndex, -// appGenesisState.ApplicationList..., -// ) -// -// // need to wait for the account to be initialized in the next block -// require.NoError(t, net.WaitForNextBlock()) -//} -// -//// TODO_IN_THIS_COMMIT: integrate with inMemoryNetworkWithSessions? -//func initSupplierAccountsWithSequence( -// t *testing.T, -// net *sdknetwork.Network, -// sequenceIdx *int32, -// supplierList ...sharedtypes.Supplier, -//) { -// t.Helper() -// -// for _, supplier := range supplierList { -// supplierAddr, err := types.AccAddressFromBech32(supplier.GetAddress()) -// require.NoError(t, err) -// InitAccountWithSequence(t, net, supplierAddr, int(*sequenceIdx)) -// atomic.AddInt32(sequenceIdx, 1) -// } -//} -// -//func initAppAccountsWithSequence( -// t *testing.T, -// net *sdknetwork.Network, -// sequenceIdx *int32, -// appList ...apptypes.Application, -//) { -// t.Helper() -// -// for _, application := range appList { -// appAddr, err := types.AccAddressFromBech32(application.GetAddress()) -// require.NoError(t, err) -// InitAccountWithSequence(t, net, appAddr, int(*sequenceIdx)) -// atomic.AddInt32(sequenceIdx, 1) -// } -//} -// -//// InitAccountWithSequence initializes an Account by sending it some funds from -//// the validator in the network to the address provided -//func InitAccountWithSequence( -// t *testing.T, -// net *sdknetwork.Network, -// addr types.AccAddress, -// signatureSequencerNumber int, -//) { -// t.Helper() -// -// val := net.Validators[0] -// signerAccountNumber := 0 -// ctx := val.ClientCtx -// args := []string{ -// fmt.Sprintf("--%s=true", flags.FlagOffline), -// fmt.Sprintf("--%s=%d", flags.FlagAccountNumber, signerAccountNumber), -// fmt.Sprintf("--%s=%d", flags.FlagSequence, signatureSequencerNumber), -// -// fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), -// fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), -// fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), -// fmt.Sprintf("--%s=%s", flags.FlagFees, types.NewCoins(types.NewCoin(net.Config.BondDenom, math.NewInt(10))).String()), -// } -// amount := types.NewCoins(types.NewCoin("stake", math.NewInt(200))) -// responseRaw, err := testcli.MsgSendExec(ctx, val.Address, addr, amount, 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) -//} From 35cd36a053cba59ad8c597d4a8f7138a33f4e3a0 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 22 Dec 2023 20:30:01 +0100 Subject: [PATCH 23/58] chore: self-review --- testutil/network/basenet/accounts.go | 46 ++++++++++++++++++-------- testutil/network/basenet/network.go | 21 +++++++++--- testutil/network/gatewaynet/network.go | 4 +-- testutil/network/genesis.go | 6 ++-- testutil/network/sessionnet/claims.go | 14 +++++--- testutil/network/sessionnet/genesis.go | 21 +++++++----- testutil/network/sessionnet/network.go | 6 ++-- testutil/network/sessionnet/proofs.go | 14 ++++---- 8 files changed, 86 insertions(+), 46 deletions(-) diff --git a/testutil/network/basenet/accounts.go b/testutil/network/basenet/accounts.go index 740935057..a8ce40209 100644 --- a/testutil/network/basenet/accounts.go +++ b/testutil/network/basenet/accounts.go @@ -27,6 +27,7 @@ const warnNoModuleGenesisFmt = "WARN: no %s module genesis state found, if this func (memnet *BaseInMemoryCosmosNetwork) CreateKeyringAccounts(t *testing.T) { t.Helper() + // Keyring MAY be provided setting InMemoryNetworkConfig#Keyring. if memnet.Config.Keyring == nil { t.Log("Keyring not initialized, using new in-memory keyring") @@ -37,61 +38,74 @@ func (memnet *BaseInMemoryCosmosNetwork) CreateKeyringAccounts(t *testing.T) { t.Log("Keyring already initialized, using existing keyring") } - // Create memnet.NumKeyringAccounts() accounts in the configured keyring. + // Create memnet.NumKeyringAccounts() number of accounts in the configured keyring. accts := testkeyring.CreatePreGeneratedKeyringAccounts( t, memnet.Config.Keyring, memnet.Config.GetNumKeyringAccounts(t), ) - // Assign the memnet's pre-generated accounts to be a new pre-generated + // Assign the memnet's pre-generated accounts to a new pre-generated // accounts iterator containing only the accounts which were also created // in the keyring. memnet.PreGeneratedAccounts = testkeyring.NewPreGeneratedAccountIterator(accts...) } +// CreateOnChainAccounts creates on-chain accounts (i.e. auth module) for the sum of +// the configured number of suppliers, applications, and gateways. func (memnet *BaseInMemoryCosmosNetwork) CreateOnChainAccounts(t *testing.T) { t.Helper() - net := memnet.GetNetwork(t) - require.NotEmptyf(t, net, "in-memory cosmos testutil network not initialized yet, call #Start() first") + // NB: while it may initially seem like the memnet#InitAccountsWithSequence() methods + // can be refactored into a generic function, this is not possible so long as the genesis + // state lists are passed directly & remain a slice of concrete types (as opposed to pointers). + // Under these conditions, a generic function would not be able to unmarshal the genesis state + // stored in the in-memory network because it is unmarshalling uses reflection, and it is not + // possible to reflect over a nil generic type value. + // Retrieve the supplier module's genesis state from cosmos-sdk in-memory network. supplierGenesisState := network.GetGenesisState[*suppliertypes.GenesisState](t, suppliertypes.ModuleName, memnet) if supplierGenesisState == nil { t.Logf(warnNoModuleGenesisFmt, "supplier") } else { + // Initialize on-chain accounts for genesis suppliers. memnet.InitSupplierAccountsWithSequence(t, supplierGenesisState.SupplierList...) } + // Retrieve the application module's genesis state from cosmos-sdk in-memory network. appGenesisState := network.GetGenesisState[*apptypes.GenesisState](t, apptypes.ModuleName, memnet) if appGenesisState == nil { t.Logf(warnNoModuleGenesisFmt, "application") } else { + // Initialize on-chain accounts for genesis applications. memnet.InitAppAccountsWithSequence(t, appGenesisState.ApplicationList...) } + // Retrieve the gateway module's genesis state from cosmos-sdk in-memory network. gatewayGenesisState := network.GetGenesisState[*gatewaytypes.GenesisState](t, gatewaytypes.ModuleName, memnet) if gatewayGenesisState == nil { t.Logf(warnNoModuleGenesisFmt, "gateway") } else { + // Initialize on-chain accounts for genesis gateways. memnet.InitGatewayAccountsWithSequence(t, gatewayGenesisState.GatewayList...) } // need to wait for the account to be initialized in the next block - require.NoError(t, net.WaitForNextBlock()) + require.NoError(t, memnet.GetNetwork(t).WaitForNextBlock()) } -// InitAccountWithSequence initializes an Account by sending it some funds from -// the validator in the network to the address provided -func (memnet *BaseInMemoryCosmosNetwork) InitAccountWithSequence( +// InitAccount initializes an Account by sending it some funds from the validator +// in the network to the address provided +func (memnet *BaseInMemoryCosmosNetwork) InitAccount( t *testing.T, addr types.AccAddress, ) { t.Helper() signerAccountNumber := 0 - // TODO_IN_THIS_COMMIT: comment.. must use validator ctx because its keyring contains the validator key. + // Validator's client context MUST be used for this CLI command because its keyring includes the validator's key clientCtx := memnet.Network.Validators[0].ClientCtx - //clientCtx := memnet.GetClientCtx(t) + // MUST NOT use memnet.GetClientCtx(t) as its keyring does not include the validator's account + // TODO_UPNEXT(@bryanchriswhite): Ensure validator key is always available via the in-memory network's keyring. net := memnet.GetNetwork(t) val := net.Validators[0] @@ -114,6 +128,8 @@ func (memnet *BaseInMemoryCosmosNetwork) InitAccountWithSequence( require.Equal(t, float64(0), responseJSON["code"], "code is not 0 in the response: %v", responseJSON) } +// InitSupplierAccountsWithSequence uses the testCLI to create on-chain accounts +// (i.e. auth module) for the addresses of the given suppliers. func (memnet *BaseInMemoryCosmosNetwork) InitSupplierAccountsWithSequence( t *testing.T, supplierList ...sharedtypes.Supplier, @@ -126,10 +142,12 @@ func (memnet *BaseInMemoryCosmosNetwork) InitSupplierAccountsWithSequence( for _, supplier := range supplierList { supplierAddr, err := types.AccAddressFromBech32(supplier.GetAddress()) require.NoError(t, err) - memnet.InitAccountWithSequence(t, supplierAddr) + memnet.InitAccount(t, supplierAddr) } } +// InitAppAccountsWithSequence uses the testCLI to create on-chain accounts +// (i.e. auth module) for the addresses of the given Applications. func (memnet *BaseInMemoryCosmosNetwork) InitAppAccountsWithSequence( t *testing.T, appList ...apptypes.Application, @@ -139,10 +157,12 @@ func (memnet *BaseInMemoryCosmosNetwork) InitAppAccountsWithSequence( for _, application := range appList { appAddr, err := types.AccAddressFromBech32(application.GetAddress()) require.NoError(t, err) - memnet.InitAccountWithSequence(t, appAddr) + memnet.InitAccount(t, appAddr) } } +// InitGatewayAccountsWithSequence uses the testCLI to create on-chain accounts +// (i.e. auth module) for the addresses of the given Gateways. func (memnet *BaseInMemoryCosmosNetwork) InitGatewayAccountsWithSequence( t *testing.T, gatewayList ...gatewaytypes.Gateway, @@ -152,6 +172,6 @@ func (memnet *BaseInMemoryCosmosNetwork) InitGatewayAccountsWithSequence( for _, gateway := range gatewayList { gatewayAddr, err := types.AccAddressFromBech32(gateway.GetAddress()) require.NoError(t, err) - memnet.InitAccountWithSequence(t, gatewayAddr) + memnet.InitAccount(t, gatewayAddr) } } diff --git a/testutil/network/basenet/network.go b/testutil/network/basenet/network.go index 789c14c24..eafeaf285 100644 --- a/testutil/network/basenet/network.go +++ b/testutil/network/basenet/network.go @@ -22,6 +22,9 @@ type BaseInMemoryCosmosNetwork struct { PreGeneratedAccounts *testkeyring.PreGeneratedAccountIterator Network *sdknetwork.Network + // lastAccountSeqNumber stores the last (most recently generated) account sequence number. + // NB: explicitly NOT using atomic.Int32 as it's usage doesn't compose well with anonymous + // literal declarations. lastAccountSeqNumber int32 } @@ -38,6 +41,9 @@ func NewBaseInMemoryCosmosNetwork( return &BaseInMemoryCosmosNetwork{ Config: *cfg, PreGeneratedAccounts: preGeneratedAccounts, + + // First functional account sequence number is 1. Starting at 0 so that + // callers can always use NextAccountSequenceNumber() (no boundary condition). lastAccountSeqNumber: int32(0), } } @@ -60,11 +66,11 @@ func (memnet *BaseInMemoryCosmosNetwork) InitializeDefaults(t *testing.T) { func (memnet *BaseInMemoryCosmosNetwork) GetClientCtx(t *testing.T) client.Context { t.Helper() - require.NotEmptyf(t, memnet.Network, "in-memory network not started yet, call BaseInMemoryCosmosNetwork#Start() first") - // Only the first validator's client context is populated. // (see: https://pkg.go.dev/github.com/cosmos/cosmos-sdk/testutil/network#pkg-overview) - ctx := memnet.Network.Validators[0].ClientCtx + ctx := memnet.GetNetwork(t).Validators[0].ClientCtx + + // TODO_UPNEXT(@bryanchriswhite): Ensure validator key is always available. // Overwrite the client context's Keyring with the in-memory one that contains // our pre-generated accounts. @@ -72,6 +78,7 @@ func (memnet *BaseInMemoryCosmosNetwork) GetClientCtx(t *testing.T) client.Conte } // GetNetworkConfig returns the underlying cosmos-sdk testutil network config. +// It requires that the config has been set, failing the test if not. func (memnet *BaseInMemoryCosmosNetwork) GetNetworkConfig(t *testing.T) *sdknetwork.Config { t.Helper() @@ -80,20 +87,24 @@ func (memnet *BaseInMemoryCosmosNetwork) GetNetworkConfig(t *testing.T) *sdknetw } // GetNetwork returns the underlying cosmos-sdk testutil network instance. +// It requires that the cosmos-sdk in-memory network has been set, failing the test if not. func (memnet *BaseInMemoryCosmosNetwork) GetNetwork(t *testing.T) *sdknetwork.Network { t.Helper() require.NotEmptyf(t, memnet.Network, "in-memory cosmos network not set") - return memnet.Network } +// GetLastAccountSequenceNumber returns the last (most recently generated) account sequence number. +// It is safe for concurrent use. func (memnet *BaseInMemoryCosmosNetwork) GetLastAccountSequenceNumber(t *testing.T) int { t.Helper() - return int(memnet.lastAccountSeqNumber) + return int(atomic.LoadInt32(&memnet.lastAccountSeqNumber)) } +// NextAccountSequenceNumber increments the account sequence number and returns the new value. +// It is safe for concurrent use. func (memnet *BaseInMemoryCosmosNetwork) NextAccountSequenceNumber(t *testing.T) int { t.Helper() diff --git a/testutil/network/gatewaynet/network.go b/testutil/network/gatewaynet/network.go index 5b24e2816..1a7e2748a 100644 --- a/testutil/network/gatewaynet/network.go +++ b/testutil/network/gatewaynet/network.go @@ -52,6 +52,7 @@ func NewInMemoryNetworkWithGateways(t *testing.T, cfg *network.InMemoryNetworkCo } } +// DelegateAppToGateway delegates the application by address to the gateway by address. func (memnet *inMemoryNetworkWithGateways) DelegateAppToGateway( t *testing.T, appBech32 string, @@ -75,6 +76,7 @@ func (memnet *inMemoryNetworkWithGateways) DelegateAppToGateway( require.Equal(t, uint32(0), resp.Code) } +// UndelegateAppFromGateway delegates the application by address from the gateway by address. func (memnet *inMemoryNetworkWithGateways) UndelegateAppFromGateway( t *testing.T, appBech32 string, @@ -97,8 +99,6 @@ func (memnet *inMemoryNetworkWithGateways) UndelegateAppFromGateway( require.Equal(t, uint32(0), resp.Code) } -// TODO_IN_THIS_COMMIT: update comment -// // Start initializes the in-memory network and performs the following setup: // - populates a new in-memory keyring with a sufficient number of pre-generated accounts. // - configures the application module's genesis state using addresses corresponding diff --git a/testutil/network/genesis.go b/testutil/network/genesis.go index 05eede88e..43cb577d6 100644 --- a/testutil/network/genesis.go +++ b/testutil/network/genesis.go @@ -8,12 +8,12 @@ import ( "github.com/stretchr/testify/require" ) -// GetGenesisState retrieves the genesis state for a given module from the -// underlying cosmos-sdk testutil network. +// GetGenesisState retrieves the genesis state for a given module from the underlying cosmos-sdk in-memory network. func GetGenesisState[T proto.Message](t *testing.T, moduleName string, memnet InMemoryCosmosNetwork) T { t.Helper() - require.NotEmptyf(t, memnet.GetNetwork(t), "in-memory network not started yet, call inMemoryNetworkWithSessions#Start() first") + // Ensure the in-memory network has been started. + _ = memnet.GetNetwork(t) var genesisState T // NB: As this function is generic, it MUST use reflect in order to unmarshal diff --git a/testutil/network/sessionnet/claims.go b/testutil/network/sessionnet/claims.go index 154034700..d5531ce77 100644 --- a/testutil/network/sessionnet/claims.go +++ b/testutil/network/sessionnet/claims.go @@ -25,14 +25,16 @@ import ( func (memnet *inMemoryNetworkWithSessions) CreateClaims( t *testing.T, ) (claims []suppliertypes.Claim, sessionTrees []relayer.SessionTree) { - // TODO_IN_THIS_COMMIT: update or remove comment. - // Create numSessions * numClaimsPerSession claims for the supplier + // For NumSessions, get the session for each application in the application + // module genesis state. Create a claim for each supplier in each session. for sessionIdx := 0; sessionIdx < memnet.Config.NumSessions; sessionIdx++ { appGenesisState := network.GetGenesisState[*apptypes.GenesisState](t, apptypes.ModuleName, memnet) var lastAppSession *sessiontypes.Session for _, application := range appGenesisState.ApplicationList { - // TODO_IN_THIS_COMMIT: comment... only using first service as second service has no suppliers staked for it. + // Use applications first service because this in-memory network's application genesis + // state is populated with applications whose first staked service matches that of + // AppToSupplierPairingRatio, and whose second services matches no supplier. serviceId := application.GetServiceConfigs()[0].GetService().GetId() lastAppSession = memnet.GetSession(t, serviceId, application.GetAddress()) @@ -45,7 +47,8 @@ func (memnet *inMemoryNetworkWithSessions) CreateClaims( sessionTrees = append(sessionTrees, sessionTree) // TODO_TECHDEBT(#196): Move this outside of the forloop so that the test iteration is faster - // TODO_IN_THIS_COMMIT: comment... this screws with the session start height... + // This interacts negatively with the session start/end heights in test scenarios. Test + // assertions may have to account for this interaction and therefore may compromise on coverage. require.NoError(t, memnet.GetNetwork(t).WaitForNextBlock()) } } @@ -65,9 +68,12 @@ func (memnet *inMemoryNetworkWithSessions) CreateClaim( clientCtx := memnet.GetClientCtx(t) net := memnet.GetNetwork(t) + // Create a new session tree with NumRelaysPerSession number of relay nodes inserted. + // Base64-encode it's root hash for use with the CLI command. sessionTree := newSessionTreeRoot(t, memnet.Config.NumRelaysPerSession, sessionHeader) rootHash, rootHashEncoded := getSessionTreeRoot(t, sessionTree) + // Base64-encode the session header for use with the CLI command. sessionHeaderEncoded := cliEncodeSessionHeader(t, sessionHeader) args := []string{ sessionHeaderEncoded, diff --git a/testutil/network/sessionnet/genesis.go b/testutil/network/sessionnet/genesis.go index c4b87d927..056d47bf4 100644 --- a/testutil/network/sessionnet/genesis.go +++ b/testutil/network/sessionnet/genesis.go @@ -12,7 +12,7 @@ import ( suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" ) -// ConfigureDefaultSupplierModuleGenesisState generates and populates the in-memory +// configureDefaultSupplierModuleGenesisState generates and populates the in-memory // network's application module's GenesisState object with a given number of suppliers, // each of which is staked for a unique service. It returns the genesis state object. func (memnet *inMemoryNetworkWithSessions) configureSupplierModuleGenesisState(t *testing.T) *suppliertypes.GenesisState { @@ -21,7 +21,7 @@ func (memnet *inMemoryNetworkWithSessions) configureSupplierModuleGenesisState(t require.NotEmptyf(t, memnet.GetNetworkConfig(t), "cosmos config not initialized, call #Start() first") require.NotEmptyf(t, memnet.PreGeneratedAccounts, "pre-generated accounts not initialized, call #Start() first") - // Create a supplier for each session in numClaimsSessions. + // Create NumSuppliers number of suppliers with a service "svcX", where "X" is the supplier's index. var supplierGenesisState = suppliertypes.DefaultGenesis() for i := 0; i < memnet.Config.NumSuppliers; i++ { preGenerateAcct, ok := memnet.PreGeneratedAccounts.Next() @@ -54,13 +54,18 @@ func (memnet *inMemoryNetworkWithSessions) configureSupplierModuleGenesisState(t return supplierGenesisState } -// TODO_IN_THIS_COMMIT: draw a diagram of the app/supplier/service session network. +// TODO_IMPROVE: draw a mermaid diagram of the app/supplier/service session network. -// ConfigureDefaultApplicationModuleGenesisState generates a GenesisState object -// with a given number of applications which are staked for a service such that -// memnet.Config.AppSupplierPairingRatio*NumSuppliers number of applications are -// staked for each supplier's service (assumes that each supplier is staked for -// a unique service with no overlap). +// configureDefaultSupplierModuleGenesisState generates and populates the in-memory +// network's application module's GenesisState object with a given number of suppliers, +// each of which is staked for a unique service. It returns the genesis state object. + +// configureDefaultApplicationModuleGenesisState generates and populates the in-memory +// network's applicaion module's GenesisState object with a given number of applications, +// each of which is staked for a service such that +// memnet.Config.AppSupplierPairingRatio*NumSuppliers number of applications are staked +// for each genesis supplier's service (assumes that each supplier is staked for a unique +// service with no overlap). func (memnet *inMemoryNetworkWithSessions) configureAppModuleGenesisState(t *testing.T) *apptypes.GenesisState { t.Helper() diff --git a/testutil/network/sessionnet/network.go b/testutil/network/sessionnet/network.go index 364c799ff..90fcae45a 100644 --- a/testutil/network/sessionnet/network.go +++ b/testutil/network/sessionnet/network.go @@ -18,8 +18,6 @@ type inMemoryNetworkWithSessions struct { basenet.BaseInMemoryCosmosNetwork } -// TODO_IN_THIS_COMMIT: consider renaming & consolidating in network/types.go -// // DefaultInMemoryNetworkConfig returns the default in-memory network configuration. // This configuration should sufficient populate on-chain objects to support reasonable // coverage around most session-oriented scenarios. @@ -57,13 +55,13 @@ func NewInMemoryNetworkWithSessions(t *testing.T, cfg *network.InMemoryNetworkCo // Start initializes the in-memory network and performs the following setup: // - populates a new in-memory keyring with a sufficient number of pre-generated accounts. // - configures the application module's genesis state using addresses corresponding -// to config.NumApplications number of the same pre-generated accounts which were +// to #GetNumApplications() number of the same pre-generated accounts which were // added to the keyring. // - configures the supplier module's genesis state using addresses corresponding to // config.NumSuppliers number of the same pre-generated accounts which were added // to the keyring. // - creates the on-chain accounts in the accounts module which correspond to the -// pre-generated accounts which were added to the keyring. +// pre-generated accounts that were added to the keyring. func (memnet *inMemoryNetworkWithSessions) Start(_ context.Context, t *testing.T) { t.Helper() diff --git a/testutil/network/sessionnet/proofs.go b/testutil/network/sessionnet/proofs.go index 26c9f2a9a..846723d4f 100644 --- a/testutil/network/sessionnet/proofs.go +++ b/testutil/network/sessionnet/proofs.go @@ -49,19 +49,19 @@ func (memnet *inMemoryNetworkWithSessions) SubmitProof( ) *types.Proof { t.Helper() - merkelProof, err := sessionTree.ProveClosest(network.TestProofPath) + closestMerkleProof, err := sessionTree.ProveClosest(network.TestProofPath) require.NoError(t, err) - proofBz, err := merkelProof.Marshal() + closestMerkleProofBz, err := closestMerkleProof.Marshal() require.NoError(t, err) sessionHeaderEncoded := cliEncodeSessionHeader(t, claim.GetSessionHeader()) - proofEncoded := base64.StdEncoding.EncodeToString(proofBz) + closestMerkleProofEncoded := base64.StdEncoding.EncodeToString(closestMerkleProofBz) bondDenom := memnet.GetNetwork(t).Config.BondDenom args := []string{ sessionHeaderEncoded, - proofEncoded, + closestMerkleProofEncoded, fmt.Sprintf("--%s=%s", flags.FlagFrom, claim.GetSupplierAddress()), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), @@ -77,9 +77,9 @@ func (memnet *inMemoryNetworkWithSessions) SubmitProof( require.Equal(t, float64(0), responseJson["code"], "code is not 0 in the response: %v", responseJson) proof := &types.Proof{ - SupplierAddress: claim.GetSupplierAddress(), - SessionHeader: claim.GetSessionHeader(), - MerkleProof: proofBz, + SupplierAddress: claim.GetSupplierAddress(), + SessionHeader: claim.GetSessionHeader(), + ClosestMerkleProof: closestMerkleProofBz, } return proof From 86f281de729dffcfecacadb9e2dc89092367e18a Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 2 Jan 2024 08:42:33 +0100 Subject: [PATCH 24/58] fix: linter errors --- testutil/network/sessionnet/network.go | 1 - testutil/network/sessionnet/proofs.go | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/testutil/network/sessionnet/network.go b/testutil/network/sessionnet/network.go index 90fcae45a..8f0b8bccd 100644 --- a/testutil/network/sessionnet/network.go +++ b/testutil/network/sessionnet/network.go @@ -27,7 +27,6 @@ func DefaultInMemoryNetworkConfig(t *testing.T) *network.InMemoryNetworkConfig { return &network.InMemoryNetworkConfig{ NumSessions: 4, NumRelaysPerSession: 5, - NumBlocksPerSession: 5, NumSuppliers: 2, AppSupplierPairingRatio: 2, } diff --git a/testutil/network/sessionnet/proofs.go b/testutil/network/sessionnet/proofs.go index 846723d4f..1491f92e2 100644 --- a/testutil/network/sessionnet/proofs.go +++ b/testutil/network/sessionnet/proofs.go @@ -13,11 +13,12 @@ import ( "github.com/stretchr/testify/require" "github.com/pokt-network/poktroll/pkg/relayer" - "github.com/pokt-network/poktroll/testutil/network" "github.com/pokt-network/poktroll/x/supplier/client/cli" "github.com/pokt-network/poktroll/x/supplier/types" ) +var TestProofPath = []byte("test_proof_path") + // SubmitProofs generates and submits a proof for each claim in the provided // list of claims. Claims are paired with session trees by index but is otherwise // arbitrary (any session tree could be used for any claim). @@ -49,7 +50,7 @@ func (memnet *inMemoryNetworkWithSessions) SubmitProof( ) *types.Proof { t.Helper() - closestMerkleProof, err := sessionTree.ProveClosest(network.TestProofPath) + closestMerkleProof, err := sessionTree.ProveClosest(TestProofPath) require.NoError(t, err) closestMerkleProofBz, err := closestMerkleProof.Marshal() From d3a21e33c3b4482148194505d32f578438135b2b Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 2 Jan 2024 13:43:00 +0100 Subject: [PATCH 25/58] chore: self-review improvements --- testutil/network/basenet/accounts.go | 19 ++++++++++++++++++- testutil/network/basenet/network.go | 10 +++++----- testutil/network/gatewaynet/network.go | 6 +++--- testutil/network/sessionnet/genesis.go | 8 ++++---- testutil/network/sessionnet/network.go | 7 +++---- 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/testutil/network/basenet/accounts.go b/testutil/network/basenet/accounts.go index a8ce40209..20b1de902 100644 --- a/testutil/network/basenet/accounts.go +++ b/testutil/network/basenet/accounts.go @@ -46,7 +46,7 @@ func (memnet *BaseInMemoryCosmosNetwork) CreateKeyringAccounts(t *testing.T) { // Assign the memnet's pre-generated accounts to a new pre-generated // accounts iterator containing only the accounts which were also created // in the keyring. - memnet.PreGeneratedAccounts = testkeyring.NewPreGeneratedAccountIterator(accts...) + memnet.PreGeneratedAccountIterator = testkeyring.NewPreGeneratedAccountIterator(accts...) } // CreateOnChainAccounts creates on-chain accounts (i.e. auth module) for the sum of @@ -128,6 +128,23 @@ func (memnet *BaseInMemoryCosmosNetwork) InitAccount( require.Equal(t, float64(0), responseJSON["code"], "code is not 0 in the response: %v", responseJSON) } +// GetPreGeneratedAccountIterator returns the pre-generated account iterator associated +// with the in-memory network; i.e. used to populate genesis and the keyring. Calling +// #Next() will return the next (unused) pre-generated account in the iterator. +func (memnet *BaseInMemoryCosmosNetwork) CreateNewOnChainAccount(t *testing.T) *testkeyring.PreGeneratedAccount { + t.Helper() + + preGeneratedAcct, ok := testkeyring.PreGeneratedAccounts().Next() + require.Truef(t, ok, "no pre-generated accounts available") + + // Create a supplier on-chain account. + memnet.InitAccount(t, preGeneratedAcct.Address) + + testkeyring.CreatePreGeneratedKeyringAccounts(t, memnet.GetClientCtx(t).Keyring, 1) + + return preGeneratedAcct +} + // InitSupplierAccountsWithSequence uses the testCLI to create on-chain accounts // (i.e. auth module) for the addresses of the given suppliers. func (memnet *BaseInMemoryCosmosNetwork) InitSupplierAccountsWithSequence( diff --git a/testutil/network/basenet/network.go b/testutil/network/basenet/network.go index eafeaf285..c1af5fea7 100644 --- a/testutil/network/basenet/network.go +++ b/testutil/network/basenet/network.go @@ -18,9 +18,9 @@ var _ network.InMemoryCosmosNetwork = (*BaseInMemoryCosmosNetwork)(nil) // BaseInMemoryCosmosNetwork is an "abstract" (i.e. partial) implementation, intended // to be embedded by other ("concrete") InMemoryCosmosNetwork implementations. type BaseInMemoryCosmosNetwork struct { - Config network.InMemoryNetworkConfig - PreGeneratedAccounts *testkeyring.PreGeneratedAccountIterator - Network *sdknetwork.Network + Config network.InMemoryNetworkConfig + PreGeneratedAccountIterator *testkeyring.PreGeneratedAccountIterator + Network *sdknetwork.Network // lastAccountSeqNumber stores the last (most recently generated) account sequence number. // NB: explicitly NOT using atomic.Int32 as it's usage doesn't compose well with anonymous @@ -39,8 +39,8 @@ func NewBaseInMemoryCosmosNetwork( t.Helper() return &BaseInMemoryCosmosNetwork{ - Config: *cfg, - PreGeneratedAccounts: preGeneratedAccounts, + Config: *cfg, + PreGeneratedAccountIterator: preGeneratedAccounts, // First functional account sequence number is 1. Starting at 0 so that // callers can always use NextAccountSequenceNumber() (no boundary condition). diff --git a/testutil/network/gatewaynet/network.go b/testutil/network/gatewaynet/network.go index 1a7e2748a..251daa134 100644 --- a/testutil/network/gatewaynet/network.go +++ b/testutil/network/gatewaynet/network.go @@ -139,7 +139,7 @@ func (memnet *inMemoryNetworkWithGateways) configureGatewayModuleGenesisState(t gatewayGenesisState := gatewaytypes.DefaultGenesis() for gatewayIdx := 0; gatewayIdx < memnet.Config.NumGateways; gatewayIdx++ { stake := sdk.NewCoin("upokt", sdk.NewInt(int64(gatewayIdx))) - preGeneratedAcct, ok := memnet.PreGeneratedAccounts.Next() + preGeneratedAcct, ok := memnet.PreGeneratedAccountIterator.Next() require.Truef(t, ok, "pre-generated accounts iterator exhausted") require.Truef(t, ok, "pre-generated accounts iterator exhausted") @@ -164,11 +164,11 @@ func (memnet *inMemoryNetworkWithGateways) configureAppModuleGenesisState(t *tes t.Helper() require.NotEmptyf(t, memnet.GetNetworkConfig(t), "cosmos config not initialized, call #Start() first") - require.NotEmptyf(t, memnet.PreGeneratedAccounts, "pre-generated accounts not initialized, call #Start() first") + require.NotEmptyf(t, memnet.PreGeneratedAccountIterator, "pre-generated accounts not initialized, call #Start() first") var appGenesisState = apptypes.DefaultGenesis() for appIdx := 0; appIdx < memnet.Config.GetNumApplications(t); appIdx++ { - preGeneratedAcct, ok := memnet.PreGeneratedAccounts.Next() + preGeneratedAcct, ok := memnet.PreGeneratedAccountIterator.Next() require.Truef(t, ok, "pre-generated accounts iterator exhausted") application := apptypes.Application{ diff --git a/testutil/network/sessionnet/genesis.go b/testutil/network/sessionnet/genesis.go index 056d47bf4..0435258ba 100644 --- a/testutil/network/sessionnet/genesis.go +++ b/testutil/network/sessionnet/genesis.go @@ -19,12 +19,12 @@ func (memnet *inMemoryNetworkWithSessions) configureSupplierModuleGenesisState(t t.Helper() require.NotEmptyf(t, memnet.GetNetworkConfig(t), "cosmos config not initialized, call #Start() first") - require.NotEmptyf(t, memnet.PreGeneratedAccounts, "pre-generated accounts not initialized, call #Start() first") + require.NotEmptyf(t, memnet.PreGeneratedAccountIterator, "pre-generated accounts not initialized, call #Start() first") // Create NumSuppliers number of suppliers with a service "svcX", where "X" is the supplier's index. var supplierGenesisState = suppliertypes.DefaultGenesis() for i := 0; i < memnet.Config.NumSuppliers; i++ { - preGenerateAcct, ok := memnet.PreGeneratedAccounts.Next() + preGenerateAcct, ok := memnet.PreGeneratedAccountIterator.Next() require.True(t, ok) supplier := sharedtypes.Supplier{ @@ -70,14 +70,14 @@ func (memnet *inMemoryNetworkWithSessions) configureAppModuleGenesisState(t *tes t.Helper() require.NotEmptyf(t, memnet.GetNetworkConfig(t), "cosmos config not initialized, call #Start() first") - require.NotEmptyf(t, memnet.PreGeneratedAccounts, "pre-generated accounts not initialized, call #Start() first") + require.NotEmptyf(t, memnet.PreGeneratedAccountIterator, "pre-generated accounts not initialized, call #Start() first") var ( serviceIdx = 0 appGenesisState = apptypes.DefaultGenesis() ) for i := 0; i < memnet.Config.GetNumApplications(t); i++ { - preGeneratedAcct, ok := memnet.PreGeneratedAccounts.Next() + preGeneratedAcct, ok := memnet.PreGeneratedAccountIterator.Next() require.True(t, ok) application := apptypes.Application{ diff --git a/testutil/network/sessionnet/network.go b/testutil/network/sessionnet/network.go index 8f0b8bccd..1049a5b57 100644 --- a/testutil/network/sessionnet/network.go +++ b/testutil/network/sessionnet/network.go @@ -44,10 +44,9 @@ func NewInMemoryNetworkWithSessions(t *testing.T, cfg *network.InMemoryNetworkCo t.Helper() return &inMemoryNetworkWithSessions{ - BaseInMemoryCosmosNetwork: basenet.BaseInMemoryCosmosNetwork{ - Config: *cfg, - PreGeneratedAccounts: testkeyring.NewPreGeneratedAccountIterator(), - }, + BaseInMemoryCosmosNetwork: *basenet.NewBaseInMemoryCosmosNetwork( + t, cfg, testkeyring.NewPreGeneratedAccountIterator(), + ), } } From 1fbf000c529ac3f32dc07d9125786c70e215aa2b Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 2 Jan 2024 15:54:04 +0100 Subject: [PATCH 26/58] fixup! fix: linter errors --- testutil/network/sessionnet/proofs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testutil/network/sessionnet/proofs.go b/testutil/network/sessionnet/proofs.go index 1491f92e2..dbaf55e33 100644 --- a/testutil/network/sessionnet/proofs.go +++ b/testutil/network/sessionnet/proofs.go @@ -17,7 +17,7 @@ import ( "github.com/pokt-network/poktroll/x/supplier/types" ) -var TestProofPath = []byte("test_proof_path") +var TestProofPath = []byte{1, 0, 1, 0, 1, 0} // SubmitProofs generates and submits a proof for each claim in the provided // list of claims. Claims are paired with session trees by index but is otherwise From b11bbe3b06593b301e6064d519697db4824134fd Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 8 Jan 2024 13:05:53 +0100 Subject: [PATCH 27/58] chore: add TODOs --- x/supplier/keeper/msg_server_create_claim.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x/supplier/keeper/msg_server_create_claim.go b/x/supplier/keeper/msg_server_create_claim.go index 9181a526f..05e21a2e4 100644 --- a/x/supplier/keeper/msg_server_create_claim.go +++ b/x/supplier/keeper/msg_server_create_claim.go @@ -10,6 +10,9 @@ import ( ) func (k msgServer) CreateClaim(goCtx context.Context, msg *suppliertypes.MsgCreateClaim) (*suppliertypes.MsgCreateClaimResponse, error) { + // TODO_BLOCKER: Prevent Claim upserts after the ClaimWindow is closed. + // TODO_BLOCKER: Validate the signature on the Claim message corresponds to the supplier before Upserting. + ctx := sdk.UnwrapSDKContext(goCtx) logger := k.Logger(ctx).With("method", "CreateClaim") From bca059c0372f8e589616d7098b923cd0105c82a8 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 8 Jan 2024 13:19:04 +0100 Subject: [PATCH 28/58] trigger CI From c21071b9164ef6ade5296534614649e200c113cb Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 8 Jan 2024 13:41:16 +0100 Subject: [PATCH 29/58] chore: review feedback improvements Co-authored-by: Redouane Lakrache Co-authored-by: Daniel Olshansky --- testutil/network/config.go | 6 +++--- testutil/network/types.go | 4 +++- x/session/keeper/session_hydrator.go | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/testutil/network/config.go b/testutil/network/config.go index 27d06128d..1d36130e3 100644 --- a/testutil/network/config.go +++ b/testutil/network/config.go @@ -11,7 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" sdkservertypes "github.com/cosmos/cosmos-sdk/server/types" - pruninttypes "github.com/cosmos/cosmos-sdk/store/pruning/types" + pruningtypes "github.com/cosmos/cosmos-sdk/store/pruning/types" "github.com/cosmos/cosmos-sdk/testutil/network" "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" @@ -64,7 +64,7 @@ func _DefaultConfig() network.Config { 0, encoding, sims.EmptyAppOptions{}, - baseapp.SetPruning(pruninttypes.NewPruningOptionsFromString(val.GetAppConfig().Pruning)), + baseapp.SetPruning(pruningtypes.NewPruningOptionsFromString(val.GetAppConfig().Pruning)), baseapp.SetMinGasPrices(val.GetAppConfig().MinGasPrices), baseapp.SetChainID(chainID), ) @@ -78,7 +78,7 @@ func _DefaultConfig() network.Config { AccountTokens: sdk.TokensFromConsensusPower(1000, sdk.DefaultPowerReduction), StakingTokens: sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction), BondedTokens: sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction), - PruningStrategy: pruninttypes.PruningOptionNothing, + PruningStrategy: pruningtypes.PruningOptionNothing, CleanupDir: true, SigningAlgo: string(hd.Secp256k1Type), KeyringOptions: []keyring.Option{}, diff --git a/testutil/network/types.go b/testutil/network/types.go index ea40fe1d7..6edeeb5d7 100644 --- a/testutil/network/types.go +++ b/testutil/network/types.go @@ -17,8 +17,10 @@ var TestMerkleProofPath = []byte("test_proof_merkle_path") // - Creating accounts in the local keyring. // - Creating genesis state for (a) module(s). // - Executing on-chain transactions (i.e. on-chain, non-genesis state). +// - Governance parameter configuration +// - Etc... type InMemoryNetworkConfig struct { - // NumSessions is the number of sessions (with sequential start heights) for + // NumSessions is the number of sessions (with increasing start heights) for // which the network should generate claims and proofs. NumSessions int diff --git a/x/session/keeper/session_hydrator.go b/x/session/keeper/session_hydrator.go index 4842cf9ff..cae92e6c9 100644 --- a/x/session/keeper/session_hydrator.go +++ b/x/session/keeper/session_hydrator.go @@ -98,7 +98,7 @@ func (k Keeper) hydrateSessionMetadata(ctx sdk.Context, sh *sessionHydrator) err sh.session.NumBlocksPerSession = NumBlocksPerSession sh.session.SessionNumber = sh.blockHeight / NumBlocksPerSession - // NB: SessionStartBlockHeight should be aligned to NumBlocksPerSession. + // TODO_BLOCKER: SessionStartBlockHeight should be aligned to NumBlocksPerSession. sh.sessionHeader.SessionStartBlockHeight = sh.blockHeight - (sh.blockHeight % NumBlocksPerSession) sh.sessionHeader.SessionEndBlockHeight = sh.sessionHeader.SessionStartBlockHeight + NumBlocksPerSession return nil From 6515c640d54721893d693affe71a4e8086fbbca3 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 8 Jan 2024 13:45:03 +0100 Subject: [PATCH 30/58] chore: update comment --- testutil/network/config.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/testutil/network/config.go b/testutil/network/config.go index 1d36130e3..9d0654de3 100644 --- a/testutil/network/config.go +++ b/testutil/network/config.go @@ -20,7 +20,10 @@ import ( "github.com/pokt-network/poktroll/app" ) -// GetNumApplications returns the number of applications to be created in the network at genesis. +// GetNumApplications returns the number of applications to be created in the +// network at genesis. NOTE: This method is intended to compute the correct value, +// regardless of how the configuration is configured (i.e. the expectations/usage +// of it in any given in-memory network implementation). func (cfg *InMemoryNetworkConfig) GetNumApplications(t *testing.T) int { t.Helper() From 7987e14cc9467e09eee81027d76a6dc7eeda750d Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 8 Jan 2024 13:51:33 +0100 Subject: [PATCH 31/58] chore: rename InMemoryCosmosNetwork to InMemoryNetwork --- testutil/network/interface.go | 10 +++++----- testutil/network/types.go | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/testutil/network/interface.go b/testutil/network/interface.go index 79dc252da..570a8d9ee 100644 --- a/testutil/network/interface.go +++ b/testutil/network/interface.go @@ -8,17 +8,17 @@ import ( "github.com/cosmos/cosmos-sdk/testutil/network" ) -// InMemoryCosmosNetwork encapsulates the cosmos-sdk testutil network instance and -// the responsibility of initializing it, along with (optional) additional/ setup, -// in #Start(). It also provides access to additional cosmos-sdk testutil network +// InMemoryNetwork encapsulates the cosmos-sdk testutil network instance and the +// esponsibility of initializing it, along with (optional) additional/ setup, in +// #Start(). It also provides access to additional cosmos-sdk testutil network // internals via corresponding methods. -type InMemoryCosmosNetwork interface { +type InMemoryNetwork interface { // GetClientCtx returns a cosmos-sdk client.Context associated with the // underlying cosmos-sdk testutil network instance. GetClientCtx(*testing.T) client.Context // GetNetworkConfig returns the underlying cosmos-sdk testutil network config. - GetNetworkConfig(*testing.T) *network.Config + GetCosmosNetworkConfig(*testing.T) *network.Config // GetNetwork returns the underlying cosmos-sdk testutil network instance. GetNetwork(*testing.T) *network.Network diff --git a/testutil/network/types.go b/testutil/network/types.go index 6edeeb5d7..77115384b 100644 --- a/testutil/network/types.go +++ b/testutil/network/types.go @@ -9,7 +9,7 @@ import ( // which to generate a proof. var TestMerkleProofPath = []byte("test_proof_merkle_path") -// InMemoryNetworkConfig is a **SHARED** config struct for use by InMemoryCosmosNetwork +// InMemoryNetworkConfig is a **SHARED** config struct for use by InMemoryNetwork // implementations to configure themselves, provide the necessary parameters to set-up // code, and initialize the underlying cosmos-sdk testutil network. // @@ -36,13 +36,13 @@ type InMemoryNetworkConfig struct { // NumApplications is the number of applications that should be created at genesis. // Usage is mutually exclusive with AppSupplierPairingRatio. This is enforced by - // InMemoryCosmosNetwork implementations. + // InMemoryNetwork implementations. NumApplications int // AppSupplierPairingRatio is the number of applications, per supplier, that // share a serviceId (i.e. will be in the same session). // Usage is mutually exclusive with NumApplications. This is enforced by - // InMemoryCosmosNetwork implementations. + // InMemoryNetwork implementations. AppSupplierPairingRatio int // CosmosCfg is the configuration for the underlying cosmos-sdk testutil network. @@ -50,9 +50,9 @@ type InMemoryNetworkConfig struct { // Keyring is the keyring to be used by clients of the cosmos-sdk testutil network. // It is intended to be populated with a sufficient number of accounts for the - // InMemoryCosmosNetwork implementation's use cases. BaseInMemoryCosmosNetwork + // InMemoryNetwork implementation's use cases. BaseInMemoryNetwork // implements a #GetNumKeyringAccounts() for this purpose. // This keyring is associated with the cosmos client context returned from - // BaseInMemoryCosmosNetwork#GetClientCtx(). + // BaseInMemoryNetwork#GetClientCtx(). Keyring keyring.Keyring } From cdcfb7d71e64737df3aad4b8a883e2a9fbae3783 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 8 Jan 2024 13:51:56 +0100 Subject: [PATCH 32/58] chore: add #GetConfig() --- testutil/network/interface.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/testutil/network/interface.go b/testutil/network/interface.go index 570a8d9ee..38a54fd36 100644 --- a/testutil/network/interface.go +++ b/testutil/network/interface.go @@ -13,6 +13,10 @@ import ( // #Start(). It also provides access to additional cosmos-sdk testutil network // internals via corresponding methods. type InMemoryNetwork interface { + // GetConfig returns the InMemoryNetworkConfig which assiciated with a given + // InMemoryNetwork instance. + GetConfig(*testing.T) *InMemoryNetworkConfig + // GetClientCtx returns a cosmos-sdk client.Context associated with the // underlying cosmos-sdk testutil network instance. GetClientCtx(*testing.T) client.Context From 92c0a191cf654a714ee99637c7f3dae254502846 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 8 Jan 2024 14:07:28 +0100 Subject: [PATCH 33/58] chore: fix comment --- testutil/network/interface.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testutil/network/interface.go b/testutil/network/interface.go index 38a54fd36..bf460b013 100644 --- a/testutil/network/interface.go +++ b/testutil/network/interface.go @@ -21,7 +21,7 @@ type InMemoryNetwork interface { // underlying cosmos-sdk testutil network instance. GetClientCtx(*testing.T) client.Context - // GetNetworkConfig returns the underlying cosmos-sdk testutil network config. + // GetCosmosNetworkConfig returns the underlying cosmos-sdk testutil network config. GetCosmosNetworkConfig(*testing.T) *network.Config // GetNetwork returns the underlying cosmos-sdk testutil network instance. From 86548cd5d6619cab1d3cec2565cb83d039049528 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 8 Jan 2024 14:08:00 +0100 Subject: [PATCH 34/58] chore: post-merge refactor --- testutil/network/basenet/accounts.go | 14 ++++----- testutil/network/basenet/network.go | 42 +++++++++++++++----------- testutil/network/gatewaynet/network.go | 26 ++++++++-------- testutil/network/genesis.go | 6 ++-- testutil/network/sessionnet/genesis.go | 10 +++--- testutil/network/sessionnet/network.go | 10 +++--- 6 files changed, 58 insertions(+), 50 deletions(-) diff --git a/testutil/network/basenet/accounts.go b/testutil/network/basenet/accounts.go index 20b1de902..bfc9abd00 100644 --- a/testutil/network/basenet/accounts.go +++ b/testutil/network/basenet/accounts.go @@ -24,7 +24,7 @@ const warnNoModuleGenesisFmt = "WARN: no %s module genesis state found, if this // CreateKeyringAccounts populates the Keyring associated with the in-memory // network with memnet.numKeyringAccounts() number of pre-generated accounts. -func (memnet *BaseInMemoryCosmosNetwork) CreateKeyringAccounts(t *testing.T) { +func (memnet *BaseInMemoryNetwork) CreateKeyringAccounts(t *testing.T) { t.Helper() // Keyring MAY be provided setting InMemoryNetworkConfig#Keyring. @@ -51,7 +51,7 @@ func (memnet *BaseInMemoryCosmosNetwork) CreateKeyringAccounts(t *testing.T) { // CreateOnChainAccounts creates on-chain accounts (i.e. auth module) for the sum of // the configured number of suppliers, applications, and gateways. -func (memnet *BaseInMemoryCosmosNetwork) CreateOnChainAccounts(t *testing.T) { +func (memnet *BaseInMemoryNetwork) CreateOnChainAccounts(t *testing.T) { t.Helper() // NB: while it may initially seem like the memnet#InitAccountsWithSequence() methods @@ -95,7 +95,7 @@ func (memnet *BaseInMemoryCosmosNetwork) CreateOnChainAccounts(t *testing.T) { // InitAccount initializes an Account by sending it some funds from the validator // in the network to the address provided -func (memnet *BaseInMemoryCosmosNetwork) InitAccount( +func (memnet *BaseInMemoryNetwork) InitAccount( t *testing.T, addr types.AccAddress, ) { @@ -131,7 +131,7 @@ func (memnet *BaseInMemoryCosmosNetwork) InitAccount( // GetPreGeneratedAccountIterator returns the pre-generated account iterator associated // with the in-memory network; i.e. used to populate genesis and the keyring. Calling // #Next() will return the next (unused) pre-generated account in the iterator. -func (memnet *BaseInMemoryCosmosNetwork) CreateNewOnChainAccount(t *testing.T) *testkeyring.PreGeneratedAccount { +func (memnet *BaseInMemoryNetwork) CreateNewOnChainAccount(t *testing.T) *testkeyring.PreGeneratedAccount { t.Helper() preGeneratedAcct, ok := testkeyring.PreGeneratedAccounts().Next() @@ -147,7 +147,7 @@ func (memnet *BaseInMemoryCosmosNetwork) CreateNewOnChainAccount(t *testing.T) * // InitSupplierAccountsWithSequence uses the testCLI to create on-chain accounts // (i.e. auth module) for the addresses of the given suppliers. -func (memnet *BaseInMemoryCosmosNetwork) InitSupplierAccountsWithSequence( +func (memnet *BaseInMemoryNetwork) InitSupplierAccountsWithSequence( t *testing.T, supplierList ...sharedtypes.Supplier, ) { @@ -165,7 +165,7 @@ func (memnet *BaseInMemoryCosmosNetwork) InitSupplierAccountsWithSequence( // InitAppAccountsWithSequence uses the testCLI to create on-chain accounts // (i.e. auth module) for the addresses of the given Applications. -func (memnet *BaseInMemoryCosmosNetwork) InitAppAccountsWithSequence( +func (memnet *BaseInMemoryNetwork) InitAppAccountsWithSequence( t *testing.T, appList ...apptypes.Application, ) { @@ -180,7 +180,7 @@ func (memnet *BaseInMemoryCosmosNetwork) InitAppAccountsWithSequence( // InitGatewayAccountsWithSequence uses the testCLI to create on-chain accounts // (i.e. auth module) for the addresses of the given Gateways. -func (memnet *BaseInMemoryCosmosNetwork) InitGatewayAccountsWithSequence( +func (memnet *BaseInMemoryNetwork) InitGatewayAccountsWithSequence( t *testing.T, gatewayList ...gatewaytypes.Gateway, ) { diff --git a/testutil/network/basenet/network.go b/testutil/network/basenet/network.go index c1af5fea7..9f64c60e7 100644 --- a/testutil/network/basenet/network.go +++ b/testutil/network/basenet/network.go @@ -13,11 +13,11 @@ import ( "github.com/pokt-network/poktroll/testutil/testkeyring" ) -var _ network.InMemoryCosmosNetwork = (*BaseInMemoryCosmosNetwork)(nil) +var _ network.InMemoryNetwork = (*BaseInMemoryNetwork)(nil) -// BaseInMemoryCosmosNetwork is an "abstract" (i.e. partial) implementation, intended -// to be embedded by other ("concrete") InMemoryCosmosNetwork implementations. -type BaseInMemoryCosmosNetwork struct { +// BaseInMemoryNetwork is an "abstract" (i.e. partial) implementation, intended +// to be embedded by other ("concrete") InMemoryNetwork implementations. +type BaseInMemoryNetwork struct { Config network.InMemoryNetworkConfig PreGeneratedAccountIterator *testkeyring.PreGeneratedAccountIterator Network *sdknetwork.Network @@ -28,17 +28,17 @@ type BaseInMemoryCosmosNetwork struct { lastAccountSeqNumber int32 } -// NewBaseInMemoryCosmosNetwork creates a new BaseInMemoryNetwork with the given +// NewBaseInMemoryNetwork creates a new BaseInMemoryNetwork with the given // configuration and pre-generated accounts. Intended to be used in constructor -// functions of structs that embed BaseInMemoryCosmosNetwork. -func NewBaseInMemoryCosmosNetwork( +// functions of structs that embed BaseInMemoryNetwork. +func NewBaseInMemoryNetwork( t *testing.T, cfg *network.InMemoryNetworkConfig, preGeneratedAccounts *testkeyring.PreGeneratedAccountIterator, -) *BaseInMemoryCosmosNetwork { +) *BaseInMemoryNetwork { t.Helper() - return &BaseInMemoryCosmosNetwork{ + return &BaseInMemoryNetwork{ Config: *cfg, PreGeneratedAccountIterator: preGeneratedAccounts, @@ -50,7 +50,7 @@ func NewBaseInMemoryCosmosNetwork( // InitializeDefaults sets the underlying cosmos-sdk testutil network config to // a reasonable default in case one was not provided with the InMemoryNetworkConfig. -func (memnet *BaseInMemoryCosmosNetwork) InitializeDefaults(t *testing.T) { +func (memnet *BaseInMemoryNetwork) InitializeDefaults(t *testing.T) { if memnet.Config.CosmosCfg == nil { t.Log("Cosmos config not initialized, using default config") @@ -63,7 +63,7 @@ func (memnet *BaseInMemoryCosmosNetwork) InitializeDefaults(t *testing.T) { } // GetClientCtx returns the underlying cosmos-sdk testutil network's client context. -func (memnet *BaseInMemoryCosmosNetwork) GetClientCtx(t *testing.T) client.Context { +func (memnet *BaseInMemoryNetwork) GetClientCtx(t *testing.T) client.Context { t.Helper() // Only the first validator's client context is populated. @@ -77,9 +77,17 @@ func (memnet *BaseInMemoryCosmosNetwork) GetClientCtx(t *testing.T) client.Conte return ctx.WithKeyring(memnet.Config.Keyring) } -// GetNetworkConfig returns the underlying cosmos-sdk testutil network config. +// GetConfig returns the InMemoryNetworkConfig which associated with a given +// InMemoryNetwork instance. +func (memnet *BaseInMemoryNetwork) GetConfig(t *testing.T) *network.InMemoryNetworkConfig { + t.Helper() + + return &memnet.Config +} + +// GetCosmosNetworkConfig returns the underlying cosmos-sdk testutil network config. // It requires that the config has been set, failing the test if not. -func (memnet *BaseInMemoryCosmosNetwork) GetNetworkConfig(t *testing.T) *sdknetwork.Config { +func (memnet *BaseInMemoryNetwork) GetCosmosNetworkConfig(t *testing.T) *sdknetwork.Config { t.Helper() require.NotEmptyf(t, memnet.Config, "in-memory network config not set") @@ -88,7 +96,7 @@ func (memnet *BaseInMemoryCosmosNetwork) GetNetworkConfig(t *testing.T) *sdknetw // GetNetwork returns the underlying cosmos-sdk testutil network instance. // It requires that the cosmos-sdk in-memory network has been set, failing the test if not. -func (memnet *BaseInMemoryCosmosNetwork) GetNetwork(t *testing.T) *sdknetwork.Network { +func (memnet *BaseInMemoryNetwork) GetNetwork(t *testing.T) *sdknetwork.Network { t.Helper() require.NotEmptyf(t, memnet.Network, "in-memory cosmos network not set") @@ -97,7 +105,7 @@ func (memnet *BaseInMemoryCosmosNetwork) GetNetwork(t *testing.T) *sdknetwork.Ne // GetLastAccountSequenceNumber returns the last (most recently generated) account sequence number. // It is safe for concurrent use. -func (memnet *BaseInMemoryCosmosNetwork) GetLastAccountSequenceNumber(t *testing.T) int { +func (memnet *BaseInMemoryNetwork) GetLastAccountSequenceNumber(t *testing.T) int { t.Helper() return int(atomic.LoadInt32(&memnet.lastAccountSeqNumber)) @@ -105,13 +113,13 @@ func (memnet *BaseInMemoryCosmosNetwork) GetLastAccountSequenceNumber(t *testing // NextAccountSequenceNumber increments the account sequence number and returns the new value. // It is safe for concurrent use. -func (memnet *BaseInMemoryCosmosNetwork) NextAccountSequenceNumber(t *testing.T) int { +func (memnet *BaseInMemoryNetwork) NextAccountSequenceNumber(t *testing.T) int { t.Helper() return int(atomic.AddInt32(&memnet.lastAccountSeqNumber, 1)) } // Start is a stub which is expected to be implemented by embedders. It panics when called. -func (memnet *BaseInMemoryCosmosNetwork) Start(_ context.Context, t *testing.T) { +func (memnet *BaseInMemoryNetwork) Start(_ context.Context, t *testing.T) { panic("not implemented") } diff --git a/testutil/network/gatewaynet/network.go b/testutil/network/gatewaynet/network.go index 251daa134..17f58ef1a 100644 --- a/testutil/network/gatewaynet/network.go +++ b/testutil/network/gatewaynet/network.go @@ -20,12 +20,12 @@ import ( sharedtypes "github.com/pokt-network/poktroll/x/shared/types" ) -var _ network.InMemoryCosmosNetwork = (*inMemoryNetworkWithGateways)(nil) +var _ network.InMemoryNetwork = (*inMemoryNetworkWithGateways)(nil) -// inMemoryNetworkWithGateways is an implementation of the InMemoryCosmosNetwork interface. +// inMemoryNetworkWithGateways is an implementation of the InMemoryNetwork interface. type inMemoryNetworkWithGateways struct { - //baseInMemoryNetwork basenet.BaseInMemoryCosmosNetwork - basenet.BaseInMemoryCosmosNetwork + //baseInMemoryNetwork basenet.BaseInMemoryNetwork + basenet.BaseInMemoryNetwork } // DefaultInMemoryNetworkConfig returns the default in-memory network configuration. @@ -46,7 +46,7 @@ func NewInMemoryNetworkWithGateways(t *testing.T, cfg *network.InMemoryNetworkCo t.Helper() return &inMemoryNetworkWithGateways{ - BaseInMemoryCosmosNetwork: *basenet.NewBaseInMemoryCosmosNetwork( + BaseInMemoryNetwork: *basenet.NewBaseInMemoryNetwork( t, cfg, testkeyring.NewPreGeneratedAccountIterator(), ), } @@ -70,7 +70,7 @@ func (memnet *inMemoryNetworkWithGateways) DelegateAppToGateway( responseRaw, err := testcli.ExecTestCLICmd(memnet.GetClientCtx(t), cli.CmdDelegateToGateway(), args) require.NoError(t, err) var resp sdk.TxResponse - require.NoError(t, memnet.GetNetworkConfig(t).Codec.UnmarshalJSON(responseRaw.Bytes(), &resp)) + require.NoError(t, memnet.GetCosmosNetworkConfig(t).Codec.UnmarshalJSON(responseRaw.Bytes(), &resp)) require.NotNil(t, resp) require.NotNil(t, resp.TxHash) require.Equal(t, uint32(0), resp.Code) @@ -88,12 +88,12 @@ func (memnet *inMemoryNetworkWithGateways) UndelegateAppFromGateway( fmt.Sprintf("--%s=%s", flags.FlagFrom, appBech32), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(memnet.GetNetworkConfig(t).BondDenom, math.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(memnet.GetCosmosNetworkConfig(t).BondDenom, math.NewInt(10))).String()), } responseRaw, err := testcli.ExecTestCLICmd(memnet.GetClientCtx(t), cli.CmdUndelegateFromGateway(), args) require.NoError(t, err) var resp sdk.TxResponse - require.NoError(t, memnet.GetNetworkConfig(t).Codec.UnmarshalJSON(responseRaw.Bytes(), &resp)) + require.NoError(t, memnet.GetCosmosNetworkConfig(t).Codec.UnmarshalJSON(responseRaw.Bytes(), &resp)) require.NotNil(t, resp) require.NotNil(t, resp.TxHash) require.Equal(t, uint32(0), resp.Code) @@ -125,7 +125,7 @@ func (memnet *inMemoryNetworkWithGateways) Start(_ context.Context, t *testing.T memnet.configureGatewayModuleGenesisState(t) memnet.configureAppModuleGenesisState(t) - memnet.Network = network.New(t, *memnet.GetNetworkConfig(t)) + memnet.Network = network.New(t, *memnet.GetCosmosNetworkConfig(t)) memnet.CreateOnChainAccounts(t) } @@ -153,17 +153,17 @@ func (memnet *inMemoryNetworkWithGateways) configureGatewayModuleGenesisState(t gatewayGenesisState.GatewayList = append(gatewayGenesisState.GatewayList, gateway) } - gatewayGenesisBuffer, err := memnet.GetNetworkConfig(t).Codec.MarshalJSON(gatewayGenesisState) + gatewayGenesisBuffer, err := memnet.GetCosmosNetworkConfig(t).Codec.MarshalJSON(gatewayGenesisState) require.NoError(t, err) // Add supplier module genesis supplierGenesisState to the network config. - memnet.GetNetworkConfig(t).GenesisState[gatewaytypes.ModuleName] = gatewayGenesisBuffer + memnet.GetCosmosNetworkConfig(t).GenesisState[gatewaytypes.ModuleName] = gatewayGenesisBuffer } func (memnet *inMemoryNetworkWithGateways) configureAppModuleGenesisState(t *testing.T) { t.Helper() - require.NotEmptyf(t, memnet.GetNetworkConfig(t), "cosmos config not initialized, call #Start() first") + require.NotEmptyf(t, memnet.GetCosmosNetworkConfig(t), "cosmos config not initialized, call #Start() first") require.NotEmptyf(t, memnet.PreGeneratedAccountIterator, "pre-generated accounts not initialized, call #Start() first") var appGenesisState = apptypes.DefaultGenesis() @@ -186,5 +186,5 @@ func (memnet *inMemoryNetworkWithGateways) configureAppModuleGenesisState(t *tes require.NoError(t, err) // Add supplier and application module genesis appGenesisState to the network memnetConfig. - memnet.GetNetworkConfig(t).GenesisState[apptypes.ModuleName] = appGenesisBuffer + memnet.GetCosmosNetworkConfig(t).GenesisState[apptypes.ModuleName] = appGenesisBuffer } diff --git a/testutil/network/genesis.go b/testutil/network/genesis.go index 43cb577d6..2c9053012 100644 --- a/testutil/network/genesis.go +++ b/testutil/network/genesis.go @@ -9,7 +9,7 @@ import ( ) // GetGenesisState retrieves the genesis state for a given module from the underlying cosmos-sdk in-memory network. -func GetGenesisState[T proto.Message](t *testing.T, moduleName string, memnet InMemoryCosmosNetwork) T { +func GetGenesisState[T proto.Message](t *testing.T, moduleName string, memnet InMemoryNetwork) T { t.Helper() // Ensure the in-memory network has been started. @@ -22,8 +22,8 @@ func GetGenesisState[T proto.Message](t *testing.T, moduleName string, memnet In genesisStateValue := reflect.New(genesisStateType.Elem()) genesisStatePtr := genesisStateValue.Interface().(proto.Message) - genesisStateJSON := memnet.GetNetworkConfig(t).GenesisState[moduleName] - err := memnet.GetNetworkConfig(t).Codec.UnmarshalJSON(genesisStateJSON, genesisStatePtr) + genesisStateJSON := memnet.GetCosmosNetworkConfig(t).GenesisState[moduleName] + err := memnet.GetCosmosNetworkConfig(t).Codec.UnmarshalJSON(genesisStateJSON, genesisStatePtr) require.NoError(t, err) return genesisStatePtr.(T) diff --git a/testutil/network/sessionnet/genesis.go b/testutil/network/sessionnet/genesis.go index 0435258ba..435f97b34 100644 --- a/testutil/network/sessionnet/genesis.go +++ b/testutil/network/sessionnet/genesis.go @@ -18,7 +18,7 @@ import ( func (memnet *inMemoryNetworkWithSessions) configureSupplierModuleGenesisState(t *testing.T) *suppliertypes.GenesisState { t.Helper() - require.NotEmptyf(t, memnet.GetNetworkConfig(t), "cosmos config not initialized, call #Start() first") + require.NotEmptyf(t, memnet.GetCosmosNetworkConfig(t), "cosmos config not initialized, call #Start() first") require.NotEmptyf(t, memnet.PreGeneratedAccountIterator, "pre-generated accounts not initialized, call #Start() first") // Create NumSuppliers number of suppliers with a service "svcX", where "X" is the supplier's index. @@ -45,11 +45,11 @@ func (memnet *inMemoryNetworkWithSessions) configureSupplierModuleGenesisState(t supplierGenesisState.SupplierList = append(supplierGenesisState.SupplierList, supplier) } - supplierGenesisBuffer, err := memnet.GetNetworkConfig(t).Codec.MarshalJSON(supplierGenesisState) + supplierGenesisBuffer, err := memnet.GetCosmosNetworkConfig(t).Codec.MarshalJSON(supplierGenesisState) require.NoError(t, err) // Add supplier module genesis supplierGenesisState to the network config. - memnet.GetNetworkConfig(t).GenesisState[suppliertypes.ModuleName] = supplierGenesisBuffer + memnet.GetCosmosNetworkConfig(t).GenesisState[suppliertypes.ModuleName] = supplierGenesisBuffer return supplierGenesisState } @@ -69,7 +69,7 @@ func (memnet *inMemoryNetworkWithSessions) configureSupplierModuleGenesisState(t func (memnet *inMemoryNetworkWithSessions) configureAppModuleGenesisState(t *testing.T) *apptypes.GenesisState { t.Helper() - require.NotEmptyf(t, memnet.GetNetworkConfig(t), "cosmos config not initialized, call #Start() first") + require.NotEmptyf(t, memnet.GetCosmosNetworkConfig(t), "cosmos config not initialized, call #Start() first") require.NotEmptyf(t, memnet.PreGeneratedAccountIterator, "pre-generated accounts not initialized, call #Start() first") var ( @@ -103,7 +103,7 @@ func (memnet *inMemoryNetworkWithSessions) configureAppModuleGenesisState(t *tes require.NoError(t, err) // Add supplier and application module genesis appGenesisState to the network memnetConfig. - memnet.GetNetworkConfig(t).GenesisState[apptypes.ModuleName] = appGenesisBuffer + memnet.GetCosmosNetworkConfig(t).GenesisState[apptypes.ModuleName] = appGenesisBuffer return appGenesisState } diff --git a/testutil/network/sessionnet/network.go b/testutil/network/sessionnet/network.go index 1049a5b57..591e51e70 100644 --- a/testutil/network/sessionnet/network.go +++ b/testutil/network/sessionnet/network.go @@ -11,11 +11,11 @@ import ( "github.com/pokt-network/poktroll/testutil/testkeyring" ) -var _ network.InMemoryCosmosNetwork = (*inMemoryNetworkWithSessions)(nil) +var _ network.InMemoryNetwork = (*inMemoryNetworkWithSessions)(nil) -// inMemoryNetworkWithSessions is an implementation of the InMemoryCosmosNetwork interface. +// inMemoryNetworkWithSessions is an implementation of the InMemoryNetwork interface. type inMemoryNetworkWithSessions struct { - basenet.BaseInMemoryCosmosNetwork + basenet.BaseInMemoryNetwork } // DefaultInMemoryNetworkConfig returns the default in-memory network configuration. @@ -44,7 +44,7 @@ func NewInMemoryNetworkWithSessions(t *testing.T, cfg *network.InMemoryNetworkCo t.Helper() return &inMemoryNetworkWithSessions{ - BaseInMemoryCosmosNetwork: *basenet.NewBaseInMemoryCosmosNetwork( + BaseInMemoryNetwork: *basenet.NewBaseInMemoryNetwork( t, cfg, testkeyring.NewPreGeneratedAccountIterator(), ), } @@ -77,7 +77,7 @@ func (memnet *inMemoryNetworkWithSessions) Start(_ context.Context, t *testing.T memnet.configureAppModuleGenesisState(t) memnet.configureSupplierModuleGenesisState(t) - memnet.Network = network.New(t, *memnet.GetNetworkConfig(t)) + memnet.Network = network.New(t, *memnet.GetCosmosNetworkConfig(t)) err := memnet.Network.WaitForNextBlock() require.NoError(t, err) From ff09a4279f5c1721d425225f04a07c5e77b345bd Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 8 Jan 2024 14:19:04 +0100 Subject: [PATCH 35/58] chore: fix comment typo --- testutil/network/interface.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testutil/network/interface.go b/testutil/network/interface.go index bf460b013..85c1f8124 100644 --- a/testutil/network/interface.go +++ b/testutil/network/interface.go @@ -13,7 +13,7 @@ import ( // #Start(). It also provides access to additional cosmos-sdk testutil network // internals via corresponding methods. type InMemoryNetwork interface { - // GetConfig returns the InMemoryNetworkConfig which assiciated with a given + // GetConfig returns the InMemoryNetworkConfig which associated with a given // InMemoryNetwork instance. GetConfig(*testing.T) *InMemoryNetworkConfig From 9f472f6f74593258ed358c503fb24ba51b6fe0c5 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 8 Jan 2024 20:26:31 +0100 Subject: [PATCH 36/58] trigger CI From 3de19719c5c72156a91159cd4773cd71458dd10c Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 9 Jan 2024 09:52:07 +0100 Subject: [PATCH 37/58] chore: add TODO --- x/supplier/keeper/msg_server_submit_proof.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x/supplier/keeper/msg_server_submit_proof.go b/x/supplier/keeper/msg_server_submit_proof.go index 2715b7c8d..7a764a12d 100644 --- a/x/supplier/keeper/msg_server_submit_proof.go +++ b/x/supplier/keeper/msg_server_submit_proof.go @@ -9,6 +9,9 @@ import ( ) func (k msgServer) SubmitProof(goCtx context.Context, msg *types.MsgSubmitProof) (*types.MsgSubmitProofResponse, error) { + // TODO_BLOCKER: Prevent Proof upserts after the tokenomics module has processes the respective session. + // TODO_BLOCKER: Validate the signature on the Proof message corresponds to the supplier before Upserting. + ctx := sdk.UnwrapSDKContext(goCtx) if err := msg.ValidateBasic(); err != nil { From 2b325458d289b346d5720fbcf0eedf67670602ba Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 13 Dec 2023 14:53:46 +0100 Subject: [PATCH 38/58] chore: generalize ErrSupplierInvalidAddress and simplify --- x/supplier/keeper/query_claim.go | 3 +-- x/supplier/keeper/query_claim_test.go | 2 +- x/supplier/types/errors.go | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/x/supplier/keeper/query_claim.go b/x/supplier/keeper/query_claim.go index 29aee3634..4dd294adc 100644 --- a/x/supplier/keeper/query_claim.go +++ b/x/supplier/keeper/query_claim.go @@ -96,8 +96,7 @@ func (k Keeper) Claim(goCtx context.Context, req *types.QueryGetClaimRequest) (* ) if !found { err := types.ErrSupplierClaimNotFound.Wrapf("session ID %q and supplier %q", req.SessionId, req.SupplierAddress) - err = status.Error(codes.NotFound, err.Error()) - return nil, err + return nil, status.Error(codes.NotFound, err.Error()) } return &types.QueryGetClaimResponse{Claim: val}, nil diff --git a/x/supplier/keeper/query_claim_test.go b/x/supplier/keeper/query_claim_test.go index 714c23972..fac734a78 100644 --- a/x/supplier/keeper/query_claim_test.go +++ b/x/supplier/keeper/query_claim_test.go @@ -134,7 +134,7 @@ func TestClaim_QuerySingle(t *testing.T) { actualStatus, ok := status.FromError(err) require.True(t, ok) - require.ErrorIs(t, tc.expectedErr, actualStatus.Err()) + require.ErrorIs(t, actualStatus.Err(), tc.expectedErr) require.ErrorContains(t, err, tc.expectedErr.Error()) } else { require.NoError(t, err) diff --git a/x/supplier/types/errors.go b/x/supplier/types/errors.go index a1a4cb66a..5406c8e3f 100644 --- a/x/supplier/types/errors.go +++ b/x/supplier/types/errors.go @@ -9,7 +9,7 @@ import ( // x/supplier module sentinel errors var ( ErrSupplierInvalidStake = sdkerrors.Register(ModuleName, 1, "invalid supplier stake") - ErrSupplierInvalidAddress = sdkerrors.Register(ModuleName, 2, "invalid supplier address") + ErrSupplierInvalidAddress = sdkerrors.Register(ModuleName, 2, "invalid address") ErrSupplierUnauthorized = sdkerrors.Register(ModuleName, 3, "unauthorized supplier signer") ErrSupplierNotFound = sdkerrors.Register(ModuleName, 4, "supplier not found") ErrSupplierInvalidServiceConfig = sdkerrors.Register(ModuleName, 5, "invalid service config") From 03bb983ee4e9c45e738934b955fccd7262db2cbc Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 9 Jan 2024 11:28:07 +0100 Subject: [PATCH 39/58] rename: BaseInMemoryNetwork#CreateOnChainAccounts to #FundOnChainAccounts --- testutil/network/basenet/accounts.go | 4 ++-- testutil/network/gatewaynet/network.go | 2 +- testutil/network/sessionnet/network.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/testutil/network/basenet/accounts.go b/testutil/network/basenet/accounts.go index bfc9abd00..6fb89b213 100644 --- a/testutil/network/basenet/accounts.go +++ b/testutil/network/basenet/accounts.go @@ -49,9 +49,9 @@ func (memnet *BaseInMemoryNetwork) CreateKeyringAccounts(t *testing.T) { memnet.PreGeneratedAccountIterator = testkeyring.NewPreGeneratedAccountIterator(accts...) } -// CreateOnChainAccounts creates on-chain accounts (i.e. auth module) for the sum of +// FundOnChainAccounts creates on-chain accounts (i.e. auth module) for the sum of // the configured number of suppliers, applications, and gateways. -func (memnet *BaseInMemoryNetwork) CreateOnChainAccounts(t *testing.T) { +func (memnet *BaseInMemoryNetwork) FundOnChainAccounts(t *testing.T) { t.Helper() // NB: while it may initially seem like the memnet#InitAccountsWithSequence() methods diff --git a/testutil/network/gatewaynet/network.go b/testutil/network/gatewaynet/network.go index 17f58ef1a..cd44626d9 100644 --- a/testutil/network/gatewaynet/network.go +++ b/testutil/network/gatewaynet/network.go @@ -127,7 +127,7 @@ func (memnet *inMemoryNetworkWithGateways) Start(_ context.Context, t *testing.T memnet.Network = network.New(t, *memnet.GetCosmosNetworkConfig(t)) - memnet.CreateOnChainAccounts(t) + memnet.FundOnChainAccounts(t) } // TODO_IN_THIS_COMMIT: fix comment... diff --git a/testutil/network/sessionnet/network.go b/testutil/network/sessionnet/network.go index 591e51e70..997f5d65f 100644 --- a/testutil/network/sessionnet/network.go +++ b/testutil/network/sessionnet/network.go @@ -81,5 +81,5 @@ func (memnet *inMemoryNetworkWithSessions) Start(_ context.Context, t *testing.T err := memnet.Network.WaitForNextBlock() require.NoError(t, err) - memnet.CreateOnChainAccounts(t) + memnet.FundOnChainAccounts(t) } From a9c2a78232e6b10cfac34b0c4a7d5a1c03d2f9ce Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 9 Jan 2024 12:00:02 +0100 Subject: [PATCH 40/58] refactor: rename & simplify --- testutil/network/basenet/accounts.go | 45 +++++++++------------------- 1 file changed, 14 insertions(+), 31 deletions(-) diff --git a/testutil/network/basenet/accounts.go b/testutil/network/basenet/accounts.go index 6fb89b213..df469caa2 100644 --- a/testutil/network/basenet/accounts.go +++ b/testutil/network/basenet/accounts.go @@ -67,7 +67,7 @@ func (memnet *BaseInMemoryNetwork) FundOnChainAccounts(t *testing.T) { t.Logf(warnNoModuleGenesisFmt, "supplier") } else { // Initialize on-chain accounts for genesis suppliers. - memnet.InitSupplierAccountsWithSequence(t, supplierGenesisState.SupplierList...) + memnet.FundSupplierAccounts(t, supplierGenesisState.SupplierList...) } @@ -77,7 +77,7 @@ func (memnet *BaseInMemoryNetwork) FundOnChainAccounts(t *testing.T) { t.Logf(warnNoModuleGenesisFmt, "application") } else { // Initialize on-chain accounts for genesis applications. - memnet.InitAppAccountsWithSequence(t, appGenesisState.ApplicationList...) + memnet.FundAppAccounts(t, appGenesisState.ApplicationList...) } // Retrieve the gateway module's genesis state from cosmos-sdk in-memory network. @@ -86,16 +86,16 @@ func (memnet *BaseInMemoryNetwork) FundOnChainAccounts(t *testing.T) { t.Logf(warnNoModuleGenesisFmt, "gateway") } else { // Initialize on-chain accounts for genesis gateways. - memnet.InitGatewayAccountsWithSequence(t, gatewayGenesisState.GatewayList...) + memnet.FundGatewayAccounts(t, gatewayGenesisState.GatewayList...) } // need to wait for the account to be initialized in the next block require.NoError(t, memnet.GetNetwork(t).WaitForNextBlock()) } -// InitAccount initializes an Account by sending it some funds from the validator +// FundAddress initializes an Account by sending it some funds from the validator // in the network to the address provided -func (memnet *BaseInMemoryNetwork) InitAccount( +func (memnet *BaseInMemoryNetwork) FundAddress( t *testing.T, addr types.AccAddress, ) { @@ -128,26 +128,9 @@ func (memnet *BaseInMemoryNetwork) InitAccount( require.Equal(t, float64(0), responseJSON["code"], "code is not 0 in the response: %v", responseJSON) } -// GetPreGeneratedAccountIterator returns the pre-generated account iterator associated -// with the in-memory network; i.e. used to populate genesis and the keyring. Calling -// #Next() will return the next (unused) pre-generated account in the iterator. -func (memnet *BaseInMemoryNetwork) CreateNewOnChainAccount(t *testing.T) *testkeyring.PreGeneratedAccount { - t.Helper() - - preGeneratedAcct, ok := testkeyring.PreGeneratedAccounts().Next() - require.Truef(t, ok, "no pre-generated accounts available") - - // Create a supplier on-chain account. - memnet.InitAccount(t, preGeneratedAcct.Address) - - testkeyring.CreatePreGeneratedKeyringAccounts(t, memnet.GetClientCtx(t).Keyring, 1) - - return preGeneratedAcct -} - -// InitSupplierAccountsWithSequence uses the testCLI to create on-chain accounts +// FundSupplierAccounts uses the testCLI to create on-chain accounts // (i.e. auth module) for the addresses of the given suppliers. -func (memnet *BaseInMemoryNetwork) InitSupplierAccountsWithSequence( +func (memnet *BaseInMemoryNetwork) FundSupplierAccounts( t *testing.T, supplierList ...sharedtypes.Supplier, ) { @@ -159,13 +142,13 @@ func (memnet *BaseInMemoryNetwork) InitSupplierAccountsWithSequence( for _, supplier := range supplierList { supplierAddr, err := types.AccAddressFromBech32(supplier.GetAddress()) require.NoError(t, err) - memnet.InitAccount(t, supplierAddr) + memnet.FundAddress(t, supplierAddr) } } -// InitAppAccountsWithSequence uses the testCLI to create on-chain accounts +// FundAppAccounts uses the testCLI to create on-chain accounts // (i.e. auth module) for the addresses of the given Applications. -func (memnet *BaseInMemoryNetwork) InitAppAccountsWithSequence( +func (memnet *BaseInMemoryNetwork) FundAppAccounts( t *testing.T, appList ...apptypes.Application, ) { @@ -174,13 +157,13 @@ func (memnet *BaseInMemoryNetwork) InitAppAccountsWithSequence( for _, application := range appList { appAddr, err := types.AccAddressFromBech32(application.GetAddress()) require.NoError(t, err) - memnet.InitAccount(t, appAddr) + memnet.FundAddress(t, appAddr) } } -// InitGatewayAccountsWithSequence uses the testCLI to create on-chain accounts +// FundGatewayAccounts uses the testCLI to create on-chain accounts // (i.e. auth module) for the addresses of the given Gateways. -func (memnet *BaseInMemoryNetwork) InitGatewayAccountsWithSequence( +func (memnet *BaseInMemoryNetwork) FundGatewayAccounts( t *testing.T, gatewayList ...gatewaytypes.Gateway, ) { @@ -189,6 +172,6 @@ func (memnet *BaseInMemoryNetwork) InitGatewayAccountsWithSequence( for _, gateway := range gatewayList { gatewayAddr, err := types.AccAddressFromBech32(gateway.GetAddress()) require.NoError(t, err) - memnet.InitAccount(t, gatewayAddr) + memnet.FundAddress(t, gatewayAddr) } } From a92ad134c8009c97146c024c0b7d0347a8e7d22c Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 9 Jan 2024 13:27:20 +0100 Subject: [PATCH 41/58] chore: review feedback improvements --- testutil/network/basenet/accounts.go | 35 ++++++++++++++++++++------ testutil/network/basenet/network.go | 7 ++++-- testutil/network/gatewaynet/network.go | 12 ++++----- testutil/network/sessionnet/genesis.go | 19 ++++++-------- 4 files changed, 46 insertions(+), 27 deletions(-) diff --git a/testutil/network/basenet/accounts.go b/testutil/network/basenet/accounts.go index df469caa2..7f3897515 100644 --- a/testutil/network/basenet/accounts.go +++ b/testutil/network/basenet/accounts.go @@ -93,8 +93,12 @@ func (memnet *BaseInMemoryNetwork) FundOnChainAccounts(t *testing.T) { require.NoError(t, memnet.GetNetwork(t).WaitForNextBlock()) } -// FundAddress initializes an Account by sending it some funds from the validator -// in the network to the address provided +// FundAddress initializes an Account address and sequence number with the auth module +// by sending some tokens from the in-memory network validator, to the address provided. +// This is a necessary prerequesite in order for the account with the given address +// to be able to submit valid transactions (i.e. pay tx fees). +// NOTE: It DOES NOT associate a public key with the account. This will happen when a tx +// which is signed by the account is broadcast to the network for the first time. func (memnet *BaseInMemoryNetwork) FundAddress( t *testing.T, addr types.AccAddress, @@ -128,8 +132,13 @@ func (memnet *BaseInMemoryNetwork) FundAddress( require.Equal(t, float64(0), responseJSON["code"], "code is not 0 in the response: %v", responseJSON) } -// FundSupplierAccounts uses the testCLI to create on-chain accounts -// (i.e. auth module) for the addresses of the given suppliers. +// FundSupplierAccounts initializes account addresses and sequence numbers for, +// each supplier in the given list, with the auth module by sending them some tokens +// from the in-memory network validator, to the address provided. This is a necessary +// prerequisite in order for the account with the given address to be able to submit +// valid transactions (i.e. pay tx fees). +// NOTE: It DOES NOT associate a public key with the account. This will happen when a tx +// which is signed by the account is broadcast to the network for the first time. func (memnet *BaseInMemoryNetwork) FundSupplierAccounts( t *testing.T, supplierList ...sharedtypes.Supplier, @@ -146,8 +155,13 @@ func (memnet *BaseInMemoryNetwork) FundSupplierAccounts( } } -// FundAppAccounts uses the testCLI to create on-chain accounts -// (i.e. auth module) for the addresses of the given Applications. +// FundAppAccounts initializes account addresses and sequence numbers for, each +// application in the given list, with the auth module by sending them some tokens +// from the in-memory network validator, to the address provided. This is a necessary +// prerequisite in order for the account with the given address to be able to submit +// valid transactions (i.e. pay tx fees). +// NOTE: It DOES NOT associate a public key with the account. This will happen when a tx +// which is signed by the account is broadcast to the network for the first time. func (memnet *BaseInMemoryNetwork) FundAppAccounts( t *testing.T, appList ...apptypes.Application, @@ -161,8 +175,13 @@ func (memnet *BaseInMemoryNetwork) FundAppAccounts( } } -// FundGatewayAccounts uses the testCLI to create on-chain accounts -// (i.e. auth module) for the addresses of the given Gateways. +// FundGatewayAccounts initializes account addresses and sequence numbers for, each +// gateway in the given list, with the auth module by sending them some tokens +// from the in-memory network validator, to the address provided. This is a necessary +// prerequisite in order for the account with the given address to be able to submit +// valid transactions (i.e. pay tx fees). +// NOTE: It DOES NOT associate a public key with the account. This will happen when a tx +// which is signed by the account is broadcast to the network for the first time. func (memnet *BaseInMemoryNetwork) FundGatewayAccounts( t *testing.T, gatewayList ...gatewaytypes.Gateway, diff --git a/testutil/network/basenet/network.go b/testutil/network/basenet/network.go index 9f64c60e7..327f8e1ed 100644 --- a/testutil/network/basenet/network.go +++ b/testutil/network/basenet/network.go @@ -70,7 +70,7 @@ func (memnet *BaseInMemoryNetwork) GetClientCtx(t *testing.T) client.Context { // (see: https://pkg.go.dev/github.com/cosmos/cosmos-sdk/testutil/network#pkg-overview) ctx := memnet.GetNetwork(t).Validators[0].ClientCtx - // TODO_UPNEXT(@bryanchriswhite): Ensure validator key is always available. + // TODO_NEXT(@bryanchriswhite): Ensure validator key is always available. // Overwrite the client context's Keyring with the in-memory one that contains // our pre-generated accounts. @@ -119,7 +119,10 @@ func (memnet *BaseInMemoryNetwork) NextAccountSequenceNumber(t *testing.T) int { return int(atomic.AddInt32(&memnet.lastAccountSeqNumber, 1)) } -// Start is a stub which is expected to be implemented by embedders. It panics when called. +// Start is a stub which is expected to be implemented by "concrete" InMemoryNetwork +// implementations. As BaseInMemoryNetwork is intended to be an "abstract" implementation, +// it is too general to define this behavior, leaving it up to embedders. As a result, +// this function panics if it is called. func (memnet *BaseInMemoryNetwork) Start(_ context.Context, t *testing.T) { panic("not implemented") } diff --git a/testutil/network/gatewaynet/network.go b/testutil/network/gatewaynet/network.go index cd44626d9..80ad703ac 100644 --- a/testutil/network/gatewaynet/network.go +++ b/testutil/network/gatewaynet/network.go @@ -130,15 +130,17 @@ func (memnet *inMemoryNetworkWithGateways) Start(_ context.Context, t *testing.T memnet.FundOnChainAccounts(t) } -// TODO_IN_THIS_COMMIT: fix comment... -// GatewayModuleGenesisStateWithAddresses generates a GenesisState object with -// a gateway list full of gateways with the given addresses. +// configureGatewayModuleGenesisState generates and populates the in-memory network's +// +// application module's GenesisState object with the number of applications specified +// by the InMemoryConfig, each of which is staked for a unique service. It returns +// the genesis state object. func (memnet *inMemoryNetworkWithGateways) configureGatewayModuleGenesisState(t *testing.T) { t.Helper() gatewayGenesisState := gatewaytypes.DefaultGenesis() for gatewayIdx := 0; gatewayIdx < memnet.Config.NumGateways; gatewayIdx++ { - stake := sdk.NewCoin("upokt", sdk.NewInt(int64(gatewayIdx))) + stake := sdk.NewCoin("upokt", sdk.NewInt(10000)) preGeneratedAcct, ok := memnet.PreGeneratedAccountIterator.Next() require.Truef(t, ok, "pre-generated accounts iterator exhausted") require.Truef(t, ok, "pre-generated accounts iterator exhausted") @@ -148,8 +150,6 @@ func (memnet *inMemoryNetworkWithGateways) configureGatewayModuleGenesisState(t Stake: &stake, } - // TODO_CONSIDERATION: Evaluate whether we need `nullify.Fill` or if we should enforce `(gogoproto.nullable) = false` everywhere - // nullify.Fill(&gateway) gatewayGenesisState.GatewayList = append(gatewayGenesisState.GatewayList, gateway) } diff --git a/testutil/network/sessionnet/genesis.go b/testutil/network/sessionnet/genesis.go index 435f97b34..616cb4bea 100644 --- a/testutil/network/sessionnet/genesis.go +++ b/testutil/network/sessionnet/genesis.go @@ -1,3 +1,5 @@ +// TODO_IMPROVE: draw a mermaid diagram of the app/supplier/service session network. + package sessionnet import ( @@ -12,9 +14,10 @@ import ( suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" ) -// configureDefaultSupplierModuleGenesisState generates and populates the in-memory -// network's application module's GenesisState object with a given number of suppliers, -// each of which is staked for a unique service. It returns the genesis state object. +// configureSupplierModuleGenesisState generates and populates the in-memory +// network's application module's GenesisState object with the number of suppliers +// specified by the InMemoryConfig, each of which is staked for a unique service. +// It returns the genesis state object. func (memnet *inMemoryNetworkWithSessions) configureSupplierModuleGenesisState(t *testing.T) *suppliertypes.GenesisState { t.Helper() @@ -54,14 +57,8 @@ func (memnet *inMemoryNetworkWithSessions) configureSupplierModuleGenesisState(t return supplierGenesisState } -// TODO_IMPROVE: draw a mermaid diagram of the app/supplier/service session network. - -// configureDefaultSupplierModuleGenesisState generates and populates the in-memory -// network's application module's GenesisState object with a given number of suppliers, -// each of which is staked for a unique service. It returns the genesis state object. - -// configureDefaultApplicationModuleGenesisState generates and populates the in-memory -// network's applicaion module's GenesisState object with a given number of applications, +// configureApplicationModuleGenesisState generates and populates the in-memory network's +// applicaion module's GenesisState object with a given number of applications, // each of which is staked for a service such that // memnet.Config.AppSupplierPairingRatio*NumSuppliers number of applications are staked // for each genesis supplier's service (assumes that each supplier is staked for a unique From 4248b0bed16e28bcc5b92eaa044952e11c1ac346 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 10 Jan 2024 10:16:51 +0100 Subject: [PATCH 42/58] chore: review feedback improvements Co-authored-by: Daniel Olshansky --- x/supplier/client/cli/query_claim.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index b879f15c5..8524cb4ff 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -84,9 +84,11 @@ func CmdShowClaim() *cobra.Command { Short: "shows a specific claim", Long: `List a specific claim that the node being queried has access to (if it still exists). -A unique claim can be defined via a session_id that the given supplier participated in. -Claims are pruned, according to protocol parameters, some time after their respective proof has been submitted and any dispute window has elapsed. -This is done to minimize the rate state accumulation by effectively eliminating claims as a long-term factor to persistence requirements. +A unique claim can be defined via a `session_id` that the given `supplier` participated in. + +`Claims` are pruned, according to protocol parameters, some time after their respective `proof` has been submitted and any dispute window has elapsed. + +This is done to minimize the rate at which state accumulates by eliminating claims as a long-term factor to persistence requirements. Example: $ poktrolld --home=$(POKTROLLD_HOME) q claim show-claims --node $(POCKET_NODE)`, From 6d5826f8f5f533358834b3d46d63661481e0b3e7 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 10 Jan 2024 10:26:45 +0100 Subject: [PATCH 43/58] fix: usage raw string literal --- x/supplier/client/cli/query_claim.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index 8524cb4ff..6d110c0fa 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -84,9 +84,9 @@ func CmdShowClaim() *cobra.Command { Short: "shows a specific claim", Long: `List a specific claim that the node being queried has access to (if it still exists). -A unique claim can be defined via a `session_id` that the given `supplier` participated in. +A unique claim can be defined via a ` + "`session_id`" + ` that the given ` + "`supplier`" + ` participated in. -`Claims` are pruned, according to protocol parameters, some time after their respective `proof` has been submitted and any dispute window has elapsed. +` + "`Claims`" + ` are pruned, according to protocol parameters, some time after their respective ` + "`proof`" + ` has been submitted and any dispute window has elapsed. This is done to minimize the rate at which state accumulates by eliminating claims as a long-term factor to persistence requirements. From a57273ca65b69965e0ce39dbfc993f8996cb8c0e Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 10 Jan 2024 10:32:00 +0100 Subject: [PATCH 44/58] chore: review feedback improvements Co-authored-by: h5law Co-authored-by: Daniel Olshansky --- testutil/network/config.go | 3 ++- testutil/network/interface.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/testutil/network/config.go b/testutil/network/config.go index 9d0654de3..f43aaac7e 100644 --- a/testutil/network/config.go +++ b/testutil/network/config.go @@ -42,7 +42,8 @@ func (cfg *InMemoryNetworkConfig) GetNumKeyringAccounts(t *testing.T) int { } // DefaultConfig will initialize config for the network with custom application, -// genesis and single validator. All other parameters are inherited from cosmos-sdk/testutil/network.DefaultConfig +// genesis and single validator. +// All other parameters are inherited from cosmos-sdk/testutil/network.DefaultConfig. // // TODO_UPNEXT(@bryanchriswhite #285): Remove _ prefix after DebugConfig is removed from network.go. func _DefaultConfig() network.Config { diff --git a/testutil/network/interface.go b/testutil/network/interface.go index 85c1f8124..fa2c90eef 100644 --- a/testutil/network/interface.go +++ b/testutil/network/interface.go @@ -9,7 +9,7 @@ import ( ) // InMemoryNetwork encapsulates the cosmos-sdk testutil network instance and the -// esponsibility of initializing it, along with (optional) additional/ setup, in +// responsibility of initializing it, along with (optional) additional/ setup, in // #Start(). It also provides access to additional cosmos-sdk testutil network // internals via corresponding methods. type InMemoryNetwork interface { From 2f1232c53d04ecfc565b8bef5f99bffd9fa01c6b Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 10 Jan 2024 13:19:00 +0100 Subject: [PATCH 45/58] chore: review feedback improvements --- testutil/network/types.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/testutil/network/types.go b/testutil/network/types.go index 77115384b..368f3c485 100644 --- a/testutil/network/types.go +++ b/testutil/network/types.go @@ -37,12 +37,20 @@ type InMemoryNetworkConfig struct { // NumApplications is the number of applications that should be created at genesis. // Usage is mutually exclusive with AppSupplierPairingRatio. This is enforced by // InMemoryNetwork implementations. + // + // NOTE: Use #GetNumApplications() to compute the correct value, regardless of + // which field is used; in-memory network implementations SHOULD NOT modify config + // fields. #GetNumApplications() is intended to be the single source of truth. NumApplications int // AppSupplierPairingRatio is the number of applications, per supplier, that // share a serviceId (i.e. will be in the same session). // Usage is mutually exclusive with NumApplications. This is enforced by // InMemoryNetwork implementations. + // + // NOTE: Use #GetNumApplications() to compute the correct value, regardless of + // which field is used; in-memory network implementations SHOULD NOT modify config + // fields. #GetNumApplications() is intended to be the single source of truth. AppSupplierPairingRatio int // CosmosCfg is the configuration for the underlying cosmos-sdk testutil network. From afbefe709c07fb88a731cde733576bb2c49ae519 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 10 Jan 2024 14:07:49 +0100 Subject: [PATCH 46/58] trigger CI From 24afe561819fc5eced73676a86875bec89041a55 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 10 Jan 2024 15:06:45 +0100 Subject: [PATCH 47/58] chore: review feedback improvements Co-authored-by: Daniel Olshansky --- testutil/network/basenet/accounts.go | 2 +- testutil/network/basenet/network.go | 16 ++++++++-------- testutil/network/gatewaynet/network.go | 9 ++++----- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/testutil/network/basenet/accounts.go b/testutil/network/basenet/accounts.go index 7f3897515..f765f2428 100644 --- a/testutil/network/basenet/accounts.go +++ b/testutil/network/basenet/accounts.go @@ -54,7 +54,7 @@ func (memnet *BaseInMemoryNetwork) CreateKeyringAccounts(t *testing.T) { func (memnet *BaseInMemoryNetwork) FundOnChainAccounts(t *testing.T) { t.Helper() - // NB: while it may initially seem like the memnet#InitAccountsWithSequence() methods + // NB: while it may initially seem like the memnet#FundAccounts() methods // can be refactored into a generic function, this is not possible so long as the genesis // state lists are passed directly & remain a slice of concrete types (as opposed to pointers). // Under these conditions, a generic function would not be able to unmarshal the genesis state diff --git a/testutil/network/basenet/network.go b/testutil/network/basenet/network.go index 327f8e1ed..3ebc1dc04 100644 --- a/testutil/network/basenet/network.go +++ b/testutil/network/basenet/network.go @@ -51,15 +51,15 @@ func NewBaseInMemoryNetwork( // InitializeDefaults sets the underlying cosmos-sdk testutil network config to // a reasonable default in case one was not provided with the InMemoryNetworkConfig. func (memnet *BaseInMemoryNetwork) InitializeDefaults(t *testing.T) { - if memnet.Config.CosmosCfg == nil { - t.Log("Cosmos config not initialized, using default config") - - // Initialize a network config. - cfg := network.DefaultConfig() - memnet.Config.CosmosCfg = &cfg - } else { + if memnet.Config.CosmosCfg != nil { t.Log("Cosmos config already initialized, using existing config") + return } + + t.Log("Cosmos config not initialized, using default config") + // Initialize a network config. + cfg := network.DefaultConfig() + memnet.Config.CosmosCfg = &cfg } // GetClientCtx returns the underlying cosmos-sdk testutil network's client context. @@ -124,5 +124,5 @@ func (memnet *BaseInMemoryNetwork) NextAccountSequenceNumber(t *testing.T) int { // it is too general to define this behavior, leaving it up to embedders. As a result, // this function panics if it is called. func (memnet *BaseInMemoryNetwork) Start(_ context.Context, t *testing.T) { - panic("not implemented") + panic("must be implemented by struct embedders") } diff --git a/testutil/network/gatewaynet/network.go b/testutil/network/gatewaynet/network.go index 80ad703ac..b712c5ebc 100644 --- a/testutil/network/gatewaynet/network.go +++ b/testutil/network/gatewaynet/network.go @@ -29,7 +29,7 @@ type inMemoryNetworkWithGateways struct { } // DefaultInMemoryNetworkConfig returns the default in-memory network configuration. -// This configuration should sufficient populate on-chain objects to support reasonable +// This configuration should sufficiently populate on-chain objects to support reasonable // coverage around most session-oriented scenarios. func DefaultInMemoryNetworkConfig(t *testing.T) *network.InMemoryNetworkConfig { t.Helper() @@ -131,10 +131,9 @@ func (memnet *inMemoryNetworkWithGateways) Start(_ context.Context, t *testing.T } // configureGatewayModuleGenesisState generates and populates the in-memory network's -// -// application module's GenesisState object with the number of applications specified -// by the InMemoryConfig, each of which is staked for a unique service. It returns -// the genesis state object. +// application module's GenesisState object with the number of applications specified +// by the InMemoryConfig, each of which is staked for a unique service. It returns +// the genesis state object. func (memnet *inMemoryNetworkWithGateways) configureGatewayModuleGenesisState(t *testing.T) { t.Helper() From fe5e743aa5831fc99d4e97c552ff5fc76593cf90 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 10 Jan 2024 15:06:57 +0100 Subject: [PATCH 48/58] chore: review feedback improvements --- testutil/network/basenet/accounts.go | 15 +++++++++++---- testutil/network/basenet/network.go | 26 +++++++++++++------------- testutil/network/gatewaynet/network.go | 22 ++++++++++------------ testutil/network/sessionnet/claims.go | 4 +--- testutil/network/sessionnet/genesis.go | 2 +- testutil/network/sessionnet/network.go | 4 ++-- testutil/network/sessionnet/proofs.go | 6 +----- 7 files changed, 39 insertions(+), 40 deletions(-) diff --git a/testutil/network/basenet/accounts.go b/testutil/network/basenet/accounts.go index f765f2428..84a419430 100644 --- a/testutil/network/basenet/accounts.go +++ b/testutil/network/basenet/accounts.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keyring" testcli "github.com/cosmos/cosmos-sdk/testutil/cli" "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" "github.com/pokt-network/poktroll/testutil/network" @@ -107,7 +108,7 @@ func (memnet *BaseInMemoryNetwork) FundAddress( signerAccountNumber := 0 // Validator's client context MUST be used for this CLI command because its keyring includes the validator's key - clientCtx := memnet.Network.Validators[0].ClientCtx + clientCtx := memnet.GetClientCtx(t) // MUST NOT use memnet.GetClientCtx(t) as its keyring does not include the validator's account // TODO_UPNEXT(@bryanchriswhite): Ensure validator key is always available via the in-memory network's keyring. net := memnet.GetNetwork(t) @@ -116,14 +117,14 @@ func (memnet *BaseInMemoryNetwork) FundAddress( args := []string{ fmt.Sprintf("--%s=true", flags.FlagOffline), fmt.Sprintf("--%s=%d", flags.FlagAccountNumber, signerAccountNumber), - fmt.Sprintf("--%s=%d", flags.FlagSequence, memnet.NextAccountSequenceNumber(t)), + fmt.Sprintf("--%s=%d", flags.FlagSequence, memnet.NextValidatorTxSequenceNumber(t)), fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), - fmt.Sprintf("--%s=%s", flags.FlagFees, types.NewCoins(types.NewCoin(net.Config.BondDenom, math.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, memnet.NewBondDenomCoins(t, 10).String()), } - amount := types.NewCoins(types.NewCoin("stake", math.NewInt(200))) + amount := memnet.NewBondDenomCoins(t, 200) responseRaw, err := testcli.MsgSendExec(clientCtx, val.Address, addr, amount, args...) require.NoError(t, err) var responseJSON map[string]interface{} @@ -194,3 +195,9 @@ func (memnet *BaseInMemoryNetwork) FundGatewayAccounts( memnet.FundAddress(t, gatewayAddr) } } + +func (memnet *BaseInMemoryNetwork) NewBondDenomCoins(t *testing.T, numCoins int64) sdk.Coins { + t.Helper() + + sdk.NewCoins(sdk.NewCoin(memnet.GetNetwork(t).Config.BondDenom, math.NewInt(numCoins))) +} diff --git a/testutil/network/basenet/network.go b/testutil/network/basenet/network.go index 3ebc1dc04..d5f6ce66d 100644 --- a/testutil/network/basenet/network.go +++ b/testutil/network/basenet/network.go @@ -20,12 +20,12 @@ var _ network.InMemoryNetwork = (*BaseInMemoryNetwork)(nil) type BaseInMemoryNetwork struct { Config network.InMemoryNetworkConfig PreGeneratedAccountIterator *testkeyring.PreGeneratedAccountIterator - Network *sdknetwork.Network + CosmosNetwork *sdknetwork.Network - // lastAccountSeqNumber stores the last (most recently generated) account sequence number. + // lastValidatorSeqNumber stores the last (most recently generated) account sequence number. // NB: explicitly NOT using atomic.Int32 as it's usage doesn't compose well with anonymous // literal declarations. - lastAccountSeqNumber int32 + lastValidatorSeqNumber int32 } // NewBaseInMemoryNetwork creates a new BaseInMemoryNetwork with the given @@ -43,8 +43,8 @@ func NewBaseInMemoryNetwork( PreGeneratedAccountIterator: preGeneratedAccounts, // First functional account sequence number is 1. Starting at 0 so that - // callers can always use NextAccountSequenceNumber() (no boundary condition). - lastAccountSeqNumber: int32(0), + // callers can always use NextValidatorTxSequenceNumber() (no boundary condition). + lastValidatorSeqNumber: int32(0), } } @@ -99,24 +99,24 @@ func (memnet *BaseInMemoryNetwork) GetCosmosNetworkConfig(t *testing.T) *sdknetw func (memnet *BaseInMemoryNetwork) GetNetwork(t *testing.T) *sdknetwork.Network { t.Helper() - require.NotEmptyf(t, memnet.Network, "in-memory cosmos network not set") - return memnet.Network + require.NotEmptyf(t, memnet.CosmosNetwork, "in-memory cosmos network not set") + return memnet.CosmosNetwork } -// GetLastAccountSequenceNumber returns the last (most recently generated) account sequence number. +// GetLastValidatorTxSequenceNumber returns the last (most recently generated) account sequence number. // It is safe for concurrent use. -func (memnet *BaseInMemoryNetwork) GetLastAccountSequenceNumber(t *testing.T) int { +func (memnet *BaseInMemoryNetwork) GetLastValidatorTxSequenceNumber(t *testing.T) int { t.Helper() - return int(atomic.LoadInt32(&memnet.lastAccountSeqNumber)) + return int(atomic.LoadInt32(&memnet.lastValidatorSeqNumber)) } -// NextAccountSequenceNumber increments the account sequence number and returns the new value. +// NextValidatorTxSequenceNumber increments the account sequence number and returns the new value. // It is safe for concurrent use. -func (memnet *BaseInMemoryNetwork) NextAccountSequenceNumber(t *testing.T) int { +func (memnet *BaseInMemoryNetwork) NextValidatorTxSequenceNumber(t *testing.T) int { t.Helper() - return int(atomic.AddInt32(&memnet.lastAccountSeqNumber, 1)) + return int(atomic.AddInt32(&memnet.lastValidatorSeqNumber, 1)) } // Start is a stub which is expected to be implemented by "concrete" InMemoryNetwork diff --git a/testutil/network/gatewaynet/network.go b/testutil/network/gatewaynet/network.go index b712c5ebc..1f4b91b7b 100644 --- a/testutil/network/gatewaynet/network.go +++ b/testutil/network/gatewaynet/network.go @@ -5,7 +5,6 @@ import ( "fmt" "testing" - "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/client/flags" testcli "github.com/cosmos/cosmos-sdk/testutil/cli" sdk "github.com/cosmos/cosmos-sdk/types" @@ -24,7 +23,6 @@ var _ network.InMemoryNetwork = (*inMemoryNetworkWithGateways)(nil) // inMemoryNetworkWithGateways is an implementation of the InMemoryNetwork interface. type inMemoryNetworkWithGateways struct { - //baseInMemoryNetwork basenet.BaseInMemoryNetwork basenet.BaseInMemoryNetwork } @@ -55,17 +53,17 @@ func NewInMemoryNetworkWithGateways(t *testing.T, cfg *network.InMemoryNetworkCo // DelegateAppToGateway delegates the application by address to the gateway by address. func (memnet *inMemoryNetworkWithGateways) DelegateAppToGateway( t *testing.T, - appBech32 string, - gatewayBech32 string, + appAddrBech32 string, + gatewayAddrBech32 string, ) { t.Helper() args := []string{ - gatewayBech32, - fmt.Sprintf("--%s=%s", flags.FlagFrom, appBech32), + gatewayAddrBech32, + fmt.Sprintf("--%s=%s", flags.FlagFrom, appAddrBech32), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(memnet.GetNetwork(t).Config.BondDenom, math.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, memnet.NewBondDenomCoins(t, 10).String()), } responseRaw, err := testcli.ExecTestCLICmd(memnet.GetClientCtx(t), cli.CmdDelegateToGateway(), args) require.NoError(t, err) @@ -88,7 +86,7 @@ func (memnet *inMemoryNetworkWithGateways) UndelegateAppFromGateway( fmt.Sprintf("--%s=%s", flags.FlagFrom, appBech32), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(memnet.GetCosmosNetworkConfig(t).BondDenom, math.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, memnet.NewBondDenomCoins(t, 10).String()), } responseRaw, err := testcli.ExecTestCLICmd(memnet.GetClientCtx(t), cli.CmdUndelegateFromGateway(), args) require.NoError(t, err) @@ -112,8 +110,8 @@ func (memnet *inMemoryNetworkWithGateways) UndelegateAppFromGateway( func (memnet *inMemoryNetworkWithGateways) Start(_ context.Context, t *testing.T) { t.Helper() - // Application module genesis state fixture data generation is independent - // of that of the supplier module. + // The number of applications is NOT a function of the number of suppliers. + // `AppSupplierPairingRatio` SHOULD NOT be used by this network implementation. if memnet.Config.AppSupplierPairingRatio > 0 { panic("AppSupplierPairingRatio must be 0 for inMemoryNetworkWithGateways, use NumApplications instead") } @@ -125,7 +123,7 @@ func (memnet *inMemoryNetworkWithGateways) Start(_ context.Context, t *testing.T memnet.configureGatewayModuleGenesisState(t) memnet.configureAppModuleGenesisState(t) - memnet.Network = network.New(t, *memnet.GetCosmosNetworkConfig(t)) + memnet.CosmosNetwork = network.New(t, *memnet.GetCosmosNetworkConfig(t)) memnet.FundOnChainAccounts(t) } @@ -184,6 +182,6 @@ func (memnet *inMemoryNetworkWithGateways) configureAppModuleGenesisState(t *tes appGenesisBuffer, err := memnet.Config.CosmosCfg.Codec.MarshalJSON(appGenesisState) require.NoError(t, err) - // Add supplier and application module genesis appGenesisState to the network memnetConfig. + // Add application module genesis appGenesisState to the network memnet cosmos config. memnet.GetCosmosNetworkConfig(t).GenesisState[apptypes.ModuleName] = appGenesisBuffer } diff --git a/testutil/network/sessionnet/claims.go b/testutil/network/sessionnet/claims.go index d5531ce77..bba5c81ce 100644 --- a/testutil/network/sessionnet/claims.go +++ b/testutil/network/sessionnet/claims.go @@ -5,10 +5,8 @@ import ( "fmt" "testing" - "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/client/flags" testcli "github.com/cosmos/cosmos-sdk/testutil/cli" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" "github.com/pokt-network/poktroll/pkg/relayer" @@ -81,7 +79,7 @@ func (memnet *inMemoryNetworkWithSessions) 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, sdk.NewCoins(sdk.NewCoin(net.Config.BondDenom, math.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, memnet.NewBondDenomCoins(t, 10).String()), } responseRaw, err := testcli.ExecTestCLICmd(clientCtx, cli.CmdCreateClaim(), args) diff --git a/testutil/network/sessionnet/genesis.go b/testutil/network/sessionnet/genesis.go index 616cb4bea..86bf5b685 100644 --- a/testutil/network/sessionnet/genesis.go +++ b/testutil/network/sessionnet/genesis.go @@ -99,7 +99,7 @@ func (memnet *inMemoryNetworkWithSessions) configureAppModuleGenesisState(t *tes appGenesisBuffer, err := memnet.Config.CosmosCfg.Codec.MarshalJSON(appGenesisState) require.NoError(t, err) - // Add supplier and application module genesis appGenesisState to the network memnetConfig. + // Add supplier and application module genesis appGenesisState to the network memnet cosmos config. memnet.GetCosmosNetworkConfig(t).GenesisState[apptypes.ModuleName] = appGenesisBuffer return appGenesisState diff --git a/testutil/network/sessionnet/network.go b/testutil/network/sessionnet/network.go index 997f5d65f..e661016a8 100644 --- a/testutil/network/sessionnet/network.go +++ b/testutil/network/sessionnet/network.go @@ -77,8 +77,8 @@ func (memnet *inMemoryNetworkWithSessions) Start(_ context.Context, t *testing.T memnet.configureAppModuleGenesisState(t) memnet.configureSupplierModuleGenesisState(t) - memnet.Network = network.New(t, *memnet.GetCosmosNetworkConfig(t)) - err := memnet.Network.WaitForNextBlock() + memnet.CosmosNetwork = network.New(t, *memnet.GetCosmosNetworkConfig(t)) + err := memnet.CosmosNetwork.WaitForNextBlock() require.NoError(t, err) memnet.FundOnChainAccounts(t) diff --git a/testutil/network/sessionnet/proofs.go b/testutil/network/sessionnet/proofs.go index dbaf55e33..83d7419e9 100644 --- a/testutil/network/sessionnet/proofs.go +++ b/testutil/network/sessionnet/proofs.go @@ -6,10 +6,8 @@ import ( "fmt" "testing" - "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/client/flags" testcli "github.com/cosmos/cosmos-sdk/testutil/cli" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" "github.com/pokt-network/poktroll/pkg/relayer" @@ -58,15 +56,13 @@ func (memnet *inMemoryNetworkWithSessions) SubmitProof( sessionHeaderEncoded := cliEncodeSessionHeader(t, claim.GetSessionHeader()) closestMerkleProofEncoded := base64.StdEncoding.EncodeToString(closestMerkleProofBz) - - bondDenom := memnet.GetNetwork(t).Config.BondDenom args := []string{ sessionHeaderEncoded, closestMerkleProofEncoded, fmt.Sprintf("--%s=%s", flags.FlagFrom, claim.GetSupplierAddress()), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(bondDenom, math.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, memnet.NewBondDenomCoins(t, 10).String()), } ctx := memnet.GetClientCtx(t) From dc07730bc28e378561e0458fdf53d7b0a5005dc3 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 10 Jan 2024 15:14:05 +0100 Subject: [PATCH 49/58] fixup! chore: review feedback improvements --- testutil/network/basenet/accounts.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testutil/network/basenet/accounts.go b/testutil/network/basenet/accounts.go index 84a419430..f27350ce7 100644 --- a/testutil/network/basenet/accounts.go +++ b/testutil/network/basenet/accounts.go @@ -199,5 +199,5 @@ func (memnet *BaseInMemoryNetwork) FundGatewayAccounts( func (memnet *BaseInMemoryNetwork) NewBondDenomCoins(t *testing.T, numCoins int64) sdk.Coins { t.Helper() - sdk.NewCoins(sdk.NewCoin(memnet.GetNetwork(t).Config.BondDenom, math.NewInt(numCoins))) + return sdk.NewCoins(sdk.NewCoin(memnet.GetNetwork(t).Config.BondDenom, math.NewInt(numCoins))) } From a906d453c04d03b7ee674ed410767b66098f2dbc Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 10 Jan 2024 15:18:59 +0100 Subject: [PATCH 50/58] fix: linter errors --- testutil/network/basenet/network.go | 6 ++++-- testutil/network/sessionnet/claims.go | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/testutil/network/basenet/network.go b/testutil/network/basenet/network.go index d5f6ce66d..fb9fc6918 100644 --- a/testutil/network/basenet/network.go +++ b/testutil/network/basenet/network.go @@ -16,7 +16,9 @@ import ( var _ network.InMemoryNetwork = (*BaseInMemoryNetwork)(nil) // BaseInMemoryNetwork is an "abstract" (i.e. partial) implementation, intended -// to be embedded by other ("concrete") InMemoryNetwork implementations. +// to consolidate shared behavior between multiple ("concrete") InMemoryNetwork +// implementations. These shared behaviors (methods) are accessible to any concrete +// implementation which embeds BaseInMemoryNetwork. type BaseInMemoryNetwork struct { Config network.InMemoryNetworkConfig PreGeneratedAccountIterator *testkeyring.PreGeneratedAccountIterator @@ -55,7 +57,7 @@ func (memnet *BaseInMemoryNetwork) InitializeDefaults(t *testing.T) { t.Log("Cosmos config already initialized, using existing config") return } - + t.Log("Cosmos config not initialized, using default config") // Initialize a network config. cfg := network.DefaultConfig() diff --git a/testutil/network/sessionnet/claims.go b/testutil/network/sessionnet/claims.go index bba5c81ce..a7e7a0c68 100644 --- a/testutil/network/sessionnet/claims.go +++ b/testutil/network/sessionnet/claims.go @@ -63,9 +63,6 @@ func (memnet *inMemoryNetworkWithSessions) CreateClaim( ) (*suppliertypes.Claim, relayer.SessionTree) { t.Helper() - clientCtx := memnet.GetClientCtx(t) - net := memnet.GetNetwork(t) - // Create a new session tree with NumRelaysPerSession number of relay nodes inserted. // Base64-encode it's root hash for use with the CLI command. sessionTree := newSessionTreeRoot(t, memnet.Config.NumRelaysPerSession, sessionHeader) @@ -82,6 +79,7 @@ func (memnet *inMemoryNetworkWithSessions) CreateClaim( fmt.Sprintf("--%s=%s", flags.FlagFees, memnet.NewBondDenomCoins(t, 10).String()), } + clientCtx := memnet.GetClientCtx(t) responseRaw, err := testcli.ExecTestCLICmd(clientCtx, cli.CmdCreateClaim(), args) require.NoError(t, err) var responseJson map[string]interface{} From 12dbc57875dd5e18260cbe04ea4256bf8a79238d Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 12 Jan 2024 11:35:23 +0100 Subject: [PATCH 51/58] chore: review feedback improvements --- testutil/network/basenet/accounts.go | 3 --- testutil/network/gatewaynet/network.go | 14 ++++++++------ testutil/network/genesis.go | 2 +- testutil/network/sessionnet/genesis.go | 11 +++++------ 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/testutil/network/basenet/accounts.go b/testutil/network/basenet/accounts.go index f27350ce7..e8ef63e6d 100644 --- a/testutil/network/basenet/accounts.go +++ b/testutil/network/basenet/accounts.go @@ -107,10 +107,7 @@ func (memnet *BaseInMemoryNetwork) FundAddress( t.Helper() signerAccountNumber := 0 - // Validator's client context MUST be used for this CLI command because its keyring includes the validator's key clientCtx := memnet.GetClientCtx(t) - // MUST NOT use memnet.GetClientCtx(t) as its keyring does not include the validator's account - // TODO_UPNEXT(@bryanchriswhite): Ensure validator key is always available via the in-memory network's keyring. net := memnet.GetNetwork(t) val := net.Validators[0] diff --git a/testutil/network/gatewaynet/network.go b/testutil/network/gatewaynet/network.go index 1f4b91b7b..8a09e2f58 100644 --- a/testutil/network/gatewaynet/network.go +++ b/testutil/network/gatewaynet/network.go @@ -129,9 +129,8 @@ func (memnet *inMemoryNetworkWithGateways) Start(_ context.Context, t *testing.T } // configureGatewayModuleGenesisState generates and populates the in-memory network's -// application module's GenesisState object with the number of applications specified -// by the InMemoryConfig, each of which is staked for a unique service. It returns -// the genesis state object. +// gateway module's GenesisState object with the number of gateways specified by the +// InMemoryConfig. func (memnet *inMemoryNetworkWithGateways) configureGatewayModuleGenesisState(t *testing.T) { t.Helper() @@ -140,7 +139,6 @@ func (memnet *inMemoryNetworkWithGateways) configureGatewayModuleGenesisState(t stake := sdk.NewCoin("upokt", sdk.NewInt(10000)) preGeneratedAcct, ok := memnet.PreGeneratedAccountIterator.Next() require.Truef(t, ok, "pre-generated accounts iterator exhausted") - require.Truef(t, ok, "pre-generated accounts iterator exhausted") gateway := gatewaytypes.Gateway{ Address: preGeneratedAcct.Address.String(), @@ -153,10 +151,14 @@ func (memnet *inMemoryNetworkWithGateways) configureGatewayModuleGenesisState(t gatewayGenesisBuffer, err := memnet.GetCosmosNetworkConfig(t).Codec.MarshalJSON(gatewayGenesisState) require.NoError(t, err) - // Add supplier module genesis supplierGenesisState to the network config. + // Add gateway module genesis state to the network config. memnet.GetCosmosNetworkConfig(t).GenesisState[gatewaytypes.ModuleName] = gatewayGenesisBuffer } +// configureAppModuleGenesisState generates and populates the in-memory network's +// application module's GenesisState object with the number of applications specified +// by the InMemoryConfig, each of which is staked for a unique service. It returns +// the genesis state object. func (memnet *inMemoryNetworkWithGateways) configureAppModuleGenesisState(t *testing.T) { t.Helper() @@ -182,6 +184,6 @@ func (memnet *inMemoryNetworkWithGateways) configureAppModuleGenesisState(t *tes appGenesisBuffer, err := memnet.Config.CosmosCfg.Codec.MarshalJSON(appGenesisState) require.NoError(t, err) - // Add application module genesis appGenesisState to the network memnet cosmos config. + // Add application module genesis state to the network memnet cosmos config. memnet.GetCosmosNetworkConfig(t).GenesisState[apptypes.ModuleName] = appGenesisBuffer } diff --git a/testutil/network/genesis.go b/testutil/network/genesis.go index 2c9053012..d6ec94d74 100644 --- a/testutil/network/genesis.go +++ b/testutil/network/genesis.go @@ -17,7 +17,7 @@ func GetGenesisState[T proto.Message](t *testing.T, moduleName string, memnet In var genesisState T // NB: As this function is generic, it MUST use reflect in order to unmarshal - // the genesis state as the codec requries a reference to a concrete type pointer. + // the genesis state as the codec requires a reference to a concrete type pointer. genesisStateType := reflect.TypeOf(genesisState) genesisStateValue := reflect.New(genesisStateType.Elem()) genesisStatePtr := genesisStateValue.Interface().(proto.Message) diff --git a/testutil/network/sessionnet/genesis.go b/testutil/network/sessionnet/genesis.go index 86bf5b685..f387a2a56 100644 --- a/testutil/network/sessionnet/genesis.go +++ b/testutil/network/sessionnet/genesis.go @@ -51,18 +51,17 @@ func (memnet *inMemoryNetworkWithSessions) configureSupplierModuleGenesisState(t supplierGenesisBuffer, err := memnet.GetCosmosNetworkConfig(t).Codec.MarshalJSON(supplierGenesisState) require.NoError(t, err) - // Add supplier module genesis supplierGenesisState to the network config. + // Add supplier module genesis state to the network config. memnet.GetCosmosNetworkConfig(t).GenesisState[suppliertypes.ModuleName] = supplierGenesisBuffer return supplierGenesisState } // configureApplicationModuleGenesisState generates and populates the in-memory network's -// applicaion module's GenesisState object with a given number of applications, -// each of which is staked for a service such that -// memnet.Config.AppSupplierPairingRatio*NumSuppliers number of applications are staked -// for each genesis supplier's service (assumes that each supplier is staked for a unique -// service with no overlap). +// application module's GenesisState object with a given number of applications, each of +// which is staked for a service such that memnet.Config.AppSupplierPairingRatio*NumSuppliers +// number of applications are staked for each genesis supplier's service (assumes that each +// supplier is staked for a unique service with no overlap). func (memnet *inMemoryNetworkWithSessions) configureAppModuleGenesisState(t *testing.T) *apptypes.GenesisState { t.Helper() From c1774bf24383d3a13a5811704aaaa6ae203c9e42 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 22 Jan 2024 11:24:13 +0100 Subject: [PATCH 52/58] chore: review feedback improvements Co-authored-by: h5law --- testutil/network/basenet/accounts.go | 1 - 1 file changed, 1 deletion(-) diff --git a/testutil/network/basenet/accounts.go b/testutil/network/basenet/accounts.go index e8ef63e6d..238c0785a 100644 --- a/testutil/network/basenet/accounts.go +++ b/testutil/network/basenet/accounts.go @@ -5,7 +5,6 @@ import ( "fmt" "testing" - "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/keyring" testcli "github.com/cosmos/cosmos-sdk/testutil/cli" From 985a81727e8a2f0694a1ab761140273287ad6cf0 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 22 Jan 2024 11:24:27 +0100 Subject: [PATCH 53/58] chore: review feedback improvements Co-authored-by: h5law --- testutil/network/basenet/accounts.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testutil/network/basenet/accounts.go b/testutil/network/basenet/accounts.go index 238c0785a..85fe7b921 100644 --- a/testutil/network/basenet/accounts.go +++ b/testutil/network/basenet/accounts.go @@ -43,7 +43,7 @@ func (memnet *BaseInMemoryNetwork) CreateKeyringAccounts(t *testing.T) { t, memnet.Config.Keyring, memnet.Config.GetNumKeyringAccounts(t), ) - // Assign the memnet's pre-generated accounts to a new pre-generated + // Assign the memnet's pre-generated accounts iterator to a new pre-generated // accounts iterator containing only the accounts which were also created // in the keyring. memnet.PreGeneratedAccountIterator = testkeyring.NewPreGeneratedAccountIterator(accts...) From e905b12c7c0d398f712b46c5df1193c794b210d2 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 22 Jan 2024 11:27:07 +0100 Subject: [PATCH 54/58] chore: review feedback improvements Co-authored-by: h5law Co-authored-by: Daniel Olshansky --- testutil/network/basenet/accounts.go | 8 ++++---- testutil/network/sessionnet/claims.go | 5 ++++- testutil/network/sessionnet/genesis.go | 2 +- testutil/network/sessionnet/proofs.go | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/testutil/network/basenet/accounts.go b/testutil/network/basenet/accounts.go index 85fe7b921..101d7ad0e 100644 --- a/testutil/network/basenet/accounts.go +++ b/testutil/network/basenet/accounts.go @@ -123,9 +123,9 @@ func (memnet *BaseInMemoryNetwork) FundAddress( amount := memnet.NewBondDenomCoins(t, 200) responseRaw, err := testcli.MsgSendExec(clientCtx, val.Address, addr, amount, args...) require.NoError(t, err) - var responseJSON map[string]interface{} - err = json.Unmarshal(responseRaw.Bytes(), &responseJSON) - require.NoError(t, err) + + var responseJSON map[string]any + require.NoError(t, json.Unmarshal(responseRaw.Bytes(), &responseJSON)) require.Equal(t, float64(0), responseJSON["code"], "code is not 0 in the response: %v", responseJSON) } @@ -195,5 +195,5 @@ func (memnet *BaseInMemoryNetwork) FundGatewayAccounts( func (memnet *BaseInMemoryNetwork) NewBondDenomCoins(t *testing.T, numCoins int64) sdk.Coins { t.Helper() - return sdk.NewCoins(sdk.NewCoin(memnet.GetNetwork(t).Config.BondDenom, math.NewInt(numCoins))) + return sdk.NewCoins(sdk.NewCoin(memnet.GetNetwork(t).Config.BondDenom, sdk.NewInt(numCoins))) } diff --git a/testutil/network/sessionnet/claims.go b/testutil/network/sessionnet/claims.go index a7e7a0c68..36dea0ef7 100644 --- a/testutil/network/sessionnet/claims.go +++ b/testutil/network/sessionnet/claims.go @@ -70,6 +70,8 @@ func (memnet *inMemoryNetworkWithSessions) CreateClaim( // Base64-encode the session header for use with the CLI command. sessionHeaderEncoded := cliEncodeSessionHeader(t, sessionHeader) + + // Prepare CLI arguments args := []string{ sessionHeaderEncoded, rootHashEncoded, @@ -82,7 +84,8 @@ func (memnet *inMemoryNetworkWithSessions) CreateClaim( clientCtx := memnet.GetClientCtx(t) responseRaw, err := testcli.ExecTestCLICmd(clientCtx, cli.CmdCreateClaim(), args) require.NoError(t, err) - var responseJson map[string]interface{} + + var responseJson map[string]any 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) diff --git a/testutil/network/sessionnet/genesis.go b/testutil/network/sessionnet/genesis.go index f387a2a56..b91ad5374 100644 --- a/testutil/network/sessionnet/genesis.go +++ b/testutil/network/sessionnet/genesis.go @@ -15,7 +15,7 @@ import ( ) // configureSupplierModuleGenesisState generates and populates the in-memory -// network's application module's GenesisState object with the number of suppliers +// network's supplier module's GenesisState object with the number of suppliers // specified by the InMemoryConfig, each of which is staked for a unique service. // It returns the genesis state object. func (memnet *inMemoryNetworkWithSessions) configureSupplierModuleGenesisState(t *testing.T) *suppliertypes.GenesisState { diff --git a/testutil/network/sessionnet/proofs.go b/testutil/network/sessionnet/proofs.go index 83d7419e9..5679dcb85 100644 --- a/testutil/network/sessionnet/proofs.go +++ b/testutil/network/sessionnet/proofs.go @@ -18,7 +18,7 @@ import ( var TestProofPath = []byte{1, 0, 1, 0, 1, 0} // SubmitProofs generates and submits a proof for each claim in the provided -// list of claims. Claims are paired with session trees by index but is otherwise +// list of claims. Claims are implicitly paired with session trees by index but are otherwise // arbitrary (any session tree could be used for any claim). func (memnet *inMemoryNetworkWithSessions) SubmitProofs( t *testing.T, @@ -68,7 +68,8 @@ func (memnet *inMemoryNetworkWithSessions) SubmitProof( ctx := memnet.GetClientCtx(t) responseRaw, err := testcli.ExecTestCLICmd(ctx, cli.CmdSubmitProof(), args) require.NoError(t, err) - var responseJson map[string]interface{} + + var responseJson map[string]any 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) From 413f80e5e5829877f678615c6addf063a7f5a8da Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 22 Jan 2024 11:27:46 +0100 Subject: [PATCH 55/58] ch Co-authored-by: h5law --- testutil/network/basenet/accounts.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/testutil/network/basenet/accounts.go b/testutil/network/basenet/accounts.go index 101d7ad0e..6cc30953e 100644 --- a/testutil/network/basenet/accounts.go +++ b/testutil/network/basenet/accounts.go @@ -111,10 +111,12 @@ func (memnet *BaseInMemoryNetwork) FundAddress( val := net.Validators[0] args := []string{ + // In-memory network account flags. fmt.Sprintf("--%s=true", flags.FlagOffline), fmt.Sprintf("--%s=%d", flags.FlagAccountNumber, signerAccountNumber), fmt.Sprintf("--%s=%d", flags.FlagSequence, memnet.NextValidatorTxSequenceNumber(t)), + // Transaction related flags. fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), From 3f03074f671ae598c9864a822107f4f23ab4794b Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 22 Jan 2024 11:34:44 +0100 Subject: [PATCH 56/58] chore: review feedback improvements Co-authored-by: Daniel Olshansky --- testutil/network/sessionnet/sessions.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testutil/network/sessionnet/sessions.go b/testutil/network/sessionnet/sessions.go index b8a92c8a2..3b237dafc 100644 --- a/testutil/network/sessionnet/sessions.go +++ b/testutil/network/sessionnet/sessions.go @@ -70,7 +70,7 @@ func newSessionTreeRoot( } }) - // This function is a required constructor argument but is only called at the + // NB: This function is a required constructor argument but is only called at the // end of `sessionTree#Delete()`, which this test doesn't exercise. noop := func(header *sessiontypes.SessionHeader) {} sessionTree, err := session.NewSessionTree(sessionHeader, tmpSmtStorePath, noop) @@ -78,7 +78,7 @@ func newSessionTreeRoot( for i := 0; i < numRelays; i++ { // While these relays use the `MinedRelay` data structure, they are not - // "mined" in the sense that their inclusion is dependent on their difficulty. + // "mined" in the sense that their inclusion in the tree is guaranteed. // `MinedRelay` fixtures produced this way effectively have difficulty 0. relay := testrelayer.NewMinedRelay( t, sessionHeader.GetSessionStartBlockHeight(), @@ -94,7 +94,7 @@ func newSessionTreeRoot( // getSessionTreeRoot returns the root hash of the given sessionTree as a both a // byte slice and a base64-encoded string. -func getSessionTreeRoot( +func getEncodedSessionTreeRoot( t *testing.T, sessionTree relayer.SessionTree, ) ([]byte, string) { From 4516ff5784acaf81abf44c3bfe25e8007898e2ba Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 22 Jan 2024 11:38:25 +0100 Subject: [PATCH 57/58] chore: review feedback improvements --- testutil/network/sessionnet/claims.go | 4 +++- testutil/network/sessionnet/proofs.go | 7 +++++-- testutil/network/sessionnet/sessions.go | 7 ++++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/testutil/network/sessionnet/claims.go b/testutil/network/sessionnet/claims.go index 36dea0ef7..ff10a1d87 100644 --- a/testutil/network/sessionnet/claims.go +++ b/testutil/network/sessionnet/claims.go @@ -90,7 +90,9 @@ func (memnet *inMemoryNetworkWithSessions) 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. + // TODO_TECHDEBT: Forward the claim in the response, as opposed to constructing + // an equivalent one here once the response and respective message handler is + // updated to include it. claim := &suppliertypes.Claim{ SupplierAddress: supplierAddr, SessionHeader: sessionHeader, diff --git a/testutil/network/sessionnet/proofs.go b/testutil/network/sessionnet/proofs.go index 5679dcb85..770003797 100644 --- a/testutil/network/sessionnet/proofs.go +++ b/testutil/network/sessionnet/proofs.go @@ -15,11 +15,14 @@ import ( "github.com/pokt-network/poktroll/x/supplier/types" ) -var TestProofPath = []byte{1, 0, 1, 0, 1, 0} +var testProofPath = []byte{1, 0, 1, 0, 1, 0} // SubmitProofs generates and submits a proof for each claim in the provided // list of claims. Claims are implicitly paired with session trees by index but are otherwise // arbitrary (any session tree could be used for any claim). +// +// TODO_CONSIDERATION: This method could be refactored to accept a single list of +// objects which encapsulates both the claim and session tree. func (memnet *inMemoryNetworkWithSessions) SubmitProofs( t *testing.T, claims []types.Claim, @@ -48,7 +51,7 @@ func (memnet *inMemoryNetworkWithSessions) SubmitProof( ) *types.Proof { t.Helper() - closestMerkleProof, err := sessionTree.ProveClosest(TestProofPath) + closestMerkleProof, err := sessionTree.ProveClosest(testProofPath) require.NoError(t, err) closestMerkleProofBz, err := closestMerkleProof.Marshal() diff --git a/testutil/network/sessionnet/sessions.go b/testutil/network/sessionnet/sessions.go index 3b237dafc..587652e49 100644 --- a/testutil/network/sessionnet/sessions.go +++ b/testutil/network/sessionnet/sessions.go @@ -51,8 +51,8 @@ func cliEncodeSessionHeader(t *testing.T, sessionHeader *sessiontypes.SessionHea } // newSessionTreeRoot creates and returns a new session tree with the given number -// of relays and session header. All SMT persistence is done in a temporary and -// is cleaned up when the test completes. +// of relays and session header. All SMT persistence is done in a temporary directory +// and is cleaned up when the test completes. func newSessionTreeRoot( t *testing.T, numRelays int, @@ -79,7 +79,8 @@ func newSessionTreeRoot( for i := 0; i < numRelays; i++ { // While these relays use the `MinedRelay` data structure, they are not // "mined" in the sense that their inclusion in the tree is guaranteed. - // `MinedRelay` fixtures produced this way effectively have difficulty 0. + // `MinedRelay` fixtures produced this way have difficulty 0. + // I.e.: the on-chain mining difficulty is assumed to be 0. relay := testrelayer.NewMinedRelay( t, sessionHeader.GetSessionStartBlockHeight(), sessionHeader.GetSessionEndBlockHeight(), From 86c7133ba4036dcdd703f0e36d456451fa3ea68e Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 22 Jan 2024 11:42:45 +0100 Subject: [PATCH 58/58] fix: linter errors --- testutil/network/basenet/accounts.go | 2 +- testutil/network/sessionnet/claims.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/testutil/network/basenet/accounts.go b/testutil/network/basenet/accounts.go index 6cc30953e..d8d1ed2f3 100644 --- a/testutil/network/basenet/accounts.go +++ b/testutil/network/basenet/accounts.go @@ -125,7 +125,7 @@ func (memnet *BaseInMemoryNetwork) FundAddress( amount := memnet.NewBondDenomCoins(t, 200) responseRaw, err := testcli.MsgSendExec(clientCtx, val.Address, addr, amount, args...) require.NoError(t, err) - + var responseJSON map[string]any require.NoError(t, json.Unmarshal(responseRaw.Bytes(), &responseJSON)) require.Equal(t, float64(0), responseJSON["code"], "code is not 0 in the response: %v", responseJSON) diff --git a/testutil/network/sessionnet/claims.go b/testutil/network/sessionnet/claims.go index ff10a1d87..30f7b637e 100644 --- a/testutil/network/sessionnet/claims.go +++ b/testutil/network/sessionnet/claims.go @@ -66,7 +66,7 @@ func (memnet *inMemoryNetworkWithSessions) CreateClaim( // Create a new session tree with NumRelaysPerSession number of relay nodes inserted. // Base64-encode it's root hash for use with the CLI command. sessionTree := newSessionTreeRoot(t, memnet.Config.NumRelaysPerSession, sessionHeader) - rootHash, rootHashEncoded := getSessionTreeRoot(t, sessionTree) + rootHash, rootHashEncoded := getEncodedSessionTreeRoot(t, sessionTree) // Base64-encode the session header for use with the CLI command. sessionHeaderEncoded := cliEncodeSessionHeader(t, sessionHeader)