feat(x/accounts)!: make address generation more robust and add predictable address creation (backport #22776) (#22805)

Co-authored-by: testinginprod <98415576+testinginprod@users.noreply.github.com>
Co-authored-by: Julien Robert <julien@rbrt.fr>
This commit is contained in:
mergify[bot] 2024-12-09 16:38:55 +01:00 committed by GitHub
parent d65bc30bfd
commit 17c17b6287
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 217 additions and 81 deletions

View File

@ -32,7 +32,7 @@ func TestBaseAccount(t *testing.T) {
_, baseAccountAddr, err := ak.Init(ctx, "base", accCreator, &baseaccountv1.MsgInit{
PubKey: toAnyPb(t, privKey.PubKey()),
}, nil)
}, nil, nil)
require.NoError(t, err)
// fund base account! this will also cause an auth base account to be created

View File

@ -185,7 +185,7 @@ func initFixture(t *testing.T, f func(ctx context.Context, msg *account_abstract
banktypes.RegisterMsgServer(router, bankkeeper.NewMsgServerImpl(bankKeeper))
// init account
_, addr, err := accountsKeeper.Init(integrationApp.Context(), "mock", []byte("system"), &gogotypes.Empty{}, nil)
_, addr, err := accountsKeeper.Init(integrationApp.Context(), "mock", []byte("system"), &gogotypes.Empty{}, nil, nil)
require.NoError(t, err)
fixture := &fixture{

View File

@ -34,7 +34,7 @@ func (s *IntegrationTestSuite) TestContinuousLockingAccount() {
StartTime: currentTime,
// end time in 1 minutes
EndTime: currentTime.Add(time.Minute),
}, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))})
}, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))}, nil)
require.NoError(t, err)
addr, err := app.AuthKeeper.AddressCodec().BytesToString(randAcc)

View File

@ -33,7 +33,7 @@ func (s *IntegrationTestSuite) TestDelayedLockingAccount() {
Owner: ownerAddrStr,
// end time in 1 minutes
EndTime: currentTime.Add(time.Minute),
}, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))})
}, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))}, nil)
require.NoError(t, err)
addr, err := app.AuthKeeper.AddressCodec().BytesToString(randAcc)

View File

@ -47,7 +47,7 @@ func (s *IntegrationTestSuite) TestPeriodicLockingAccount() {
Length: time.Minute,
},
},
}, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1500))})
}, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1500))}, nil)
require.NoError(t, err)
addr, err := app.AuthKeeper.AddressCodec().BytesToString(randAcc)

View File

@ -30,7 +30,7 @@ func (s *IntegrationTestSuite) TestPermanentLockingAccount() {
_, accountAddr, err := app.AccountsKeeper.Init(ctx, lockupaccount.PERMANENT_LOCKING_ACCOUNT, accOwner, &types.MsgInitLockupAccount{
Owner: ownerAddrStr,
}, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))})
}, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))}, nil)
require.NoError(t, err)
addr, err := app.AuthKeeper.AddressCodec().BytesToString(randAcc)

View File

@ -85,7 +85,7 @@ func (s *IntegrationTestSuite) initAccount(ctx context.Context, sender []byte, m
Revote: false,
EarlyExecution: true,
},
}, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))})
}, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))}, nil)
s.NoError(err)
accountAddrStr, err := s.app.AuthKeeper.AddressCodec().BytesToString(accountAddr)

View File

@ -28,7 +28,7 @@ func TestDependencies(t *testing.T) {
_, counterAddr, err := ak.Init(ctx, "counter", accCreator, &counterv1.MsgInit{
InitialValue: 0,
}, nil)
}, nil, nil)
require.NoError(t, err)
// test dependencies
creatorInitFunds := sdk.NewCoins(sdk.NewInt64Coin("stake", 100_000))

View File

@ -74,7 +74,7 @@ func TestAuthToAccountsGRPCCompat(t *testing.T) {
// init three accounts
for n, a := range accs {
_, addr, err := f.accountsKeeper.Init(f.app.Context(), n, []byte("me"), &gogotypes.Empty{}, nil)
_, addr, err := f.accountsKeeper.Init(f.app.Context(), n, []byte("me"), &gogotypes.Empty{}, nil, nil)
require.NoError(t, err)
a.(*mockRetroCompatAccount).address = addr
}
@ -132,10 +132,10 @@ func TestAccountsBaseAccountRetroCompat(t *testing.T) {
require.NoError(t, err)
// we init two accounts to have account num not be zero.
_, _, err = f.accountsKeeper.Init(f.app.Context(), "base", []byte("me"), &basev1.MsgInit{PubKey: anyPk}, nil)
_, _, err = f.accountsKeeper.Init(f.app.Context(), "base", []byte("me"), &basev1.MsgInit{PubKey: anyPk}, nil, nil)
require.NoError(t, err)
_, addr, err := f.accountsKeeper.Init(f.app.Context(), "base", []byte("me"), &basev1.MsgInit{PubKey: anyPk}, nil)
_, addr, err := f.accountsKeeper.Init(f.app.Context(), "base", []byte("me"), &basev1.MsgInit{PubKey: anyPk}, nil, nil)
require.NoError(t, err)
// try to query it via auth

View File

@ -496,6 +496,32 @@ func (a Account) AuthRetroCompatibility(ctx context.Context, _ *authtypes.QueryL
* Implement this handler only for account types you want to expose via x/auth gRPC methods.
* The `info` field in the response can be nil if your account doesn't fit the `BaseAccount` structure.
## Address Derivation
The x/accounts module offers two methods for deriving addresses, both ensuring non-squattability. This means each address is uniquely tied to its creator, preventing address collisions between different creators (e.g., Alice cannot create addresses that would conflict with Bob's addresses).
### Method 1: Using Address Seeds
When creating an account via `MsgInit`, you can provide an `address_seed`. The address is derived using:
```bash
address = sha256(ModuleName || address_seed || creator_address)
```
### Method 2: Using Account Numbers
If no address seed is provided, the address is derived using:
```
address = sha256(ModuleName || creator_address || next_account_number)
```
### Address Seed Best Practices
1. Address seeds must be unique per creator (not globally unique)
2. Reusing an address seed will cause account creation to fail
3. For programmatic account creation, use an incrementing sequence number as the address seed
4. This is particularly useful for contracts or modules that need deterministic address generation
## Genesis
### Creating accounts on genesis

View File

@ -10,4 +10,6 @@ var (
ErrBundlerPayment = errors.New(ModuleName, 2, "bundler payment failed")
// ErrExecution is returned when the execution fails.
ErrExecution = errors.New(ModuleName, 3, "execution failed")
// ErrAccountAlreadyExists is returned when the account already exists in state.
ErrAccountAlreadyExists = errors.New(ModuleName, 4, "account already exists")
)

View File

@ -19,13 +19,13 @@ func TestGenesis(t *testing.T) {
// we init two accounts of the same type
// we set counter to 10
_, addr1, err := k.Init(ctx, testAccountType, []byte("sender"), &types.Empty{}, nil)
_, addr1, err := k.Init(ctx, testAccountType, []byte("sender"), &types.Empty{}, nil, nil)
require.NoError(t, err)
_, err = k.Execute(ctx, addr1, []byte("sender"), &types.UInt64Value{Value: 10}, nil)
require.NoError(t, err)
// we set counter to 20
_, addr2, err := k.Init(ctx, testAccountType, []byte("sender"), &types.Empty{}, nil)
_, addr2, err := k.Init(ctx, testAccountType, []byte("sender"), &types.Empty{}, nil, nil)
require.NoError(t, err)
_, err = k.Execute(ctx, addr2, []byte("sender"), &types.UInt64Value{Value: 20}, nil)
require.NoError(t, err)
@ -62,7 +62,7 @@ func TestGenesis(t *testing.T) {
require.Equal(t, &types.UInt64Value{Value: 20}, resp)
// check initted on genesis account
addr3, err := k.makeAddress(2)
addr3, err := k.makeAddress([]byte("sender-2"), 2, nil)
require.NoError(t, err)
resp, err = k.Query(ctx, addr3, &types.DoubleValue{})
require.NoError(t, err)

View File

@ -148,6 +148,7 @@ func (k Keeper) Init(
creator []byte,
initRequest transaction.Msg,
funds sdk.Coins,
addressSeed []byte,
) (transaction.Msg, []byte, error) {
// get the next account number
num, err := k.AccountNumber.Next(ctx)
@ -155,7 +156,7 @@ func (k Keeper) Init(
return nil, nil, err
}
// create address
accountAddr, err := k.makeAddress(num)
accountAddr, err := k.makeAddress(creator, num, addressSeed)
if err != nil {
return nil, nil, err
}
@ -180,7 +181,7 @@ func (k Keeper) initFromMsg(ctx context.Context, initMsg *v1.MsgInit) (transacti
}
// run account creation logic
return k.Init(ctx, initMsg.AccountType, creator, msg, initMsg.Funds)
return k.Init(ctx, initMsg.AccountType, creator, msg, initMsg.Funds, initMsg.AddressSeed)
}
// init initializes the account, given the type, the creator the newly created account number, its address and the
@ -199,8 +200,17 @@ func (k Keeper) init(
return nil, fmt.Errorf("%w: not found %s", errAccountTypeNotFound, accountType)
}
// check if account exists
alreadyExists, err := k.AccountsByType.Has(ctx, accountAddr)
if err != nil {
return nil, err
}
if alreadyExists {
return nil, ErrAccountAlreadyExists
}
// send funds, if provided
err := k.maybeSendFunds(ctx, creator, accountAddr, funds)
err = k.maybeSendFunds(ctx, creator, accountAddr, funds)
if err != nil {
return nil, fmt.Errorf("unable to transfer funds: %w", err)
}
@ -307,9 +317,26 @@ func (k Keeper) getImplementation(ctx context.Context, addr []byte) (implementat
return impl, nil
}
func (k Keeper) makeAddress(accNum uint64) ([]byte, error) {
// TODO: better address scheme, ref: https://github.com/cosmos/cosmos-sdk/issues/17516
addr := sha256.Sum256(append([]byte("x/accounts"), binary.BigEndian.AppendUint64(nil, accNum)...))
// makeAddress creates an address for the given account.
// It uses the creator address to ensure address squatting cannot happen, for example
// assuming creator sends funds to a new account X nobody can front-run that address instantiation
// unless the creator itself sends the tx.
// AddressSeed can be used to create predictable addresses, security guarantees of the above are retained.
// If address seed is not provided, the address is created using the creator and account number.
func (k Keeper) makeAddress(creator []byte, accNum uint64, addressSeed []byte) ([]byte, error) {
// in case an address seed is provided, we use it to create the address.
var seed []byte
if len(addressSeed) > 0 {
seed = append(creator, addressSeed...)
} else {
// otherwise we use the creator and account number to create the address.
seed = append(creator, binary.BigEndian.AppendUint64(nil, accNum)...)
}
moduleAndSeed := append([]byte(ModuleName), seed...)
addr := sha256.Sum256(moduleAndSeed)
return addr[:], nil
}

View File

@ -17,7 +17,7 @@ func TestKeeper_Init(t *testing.T) {
t.Run("ok", func(t *testing.T) {
sender := []byte("sender")
resp, addr, err := m.Init(ctx, "test", sender, &types.Empty{}, nil)
resp, addr, err := m.Init(ctx, "test", sender, &types.Empty{}, nil, nil)
require.NoError(t, err)
require.Equal(t, &types.Empty{}, resp)
require.NotNil(t, addr)
@ -34,7 +34,7 @@ func TestKeeper_Init(t *testing.T) {
})
t.Run("unknown account type", func(t *testing.T) {
_, _, err := m.Init(ctx, "unknown", []byte("sender"), &types.Empty{}, nil)
_, _, err := m.Init(ctx, "unknown", []byte("sender"), &types.Empty{}, nil, nil)
require.ErrorIs(t, err, errAccountTypeNotFound)
})
}
@ -44,7 +44,7 @@ func TestKeeper_Execute(t *testing.T) {
// create account
sender := []byte("sender")
_, accAddr, err := m.Init(ctx, "test", sender, &types.Empty{}, nil)
_, accAddr, err := m.Init(ctx, "test", sender, &types.Empty{}, nil, nil)
require.NoError(t, err)
t.Run("ok", func(t *testing.T) {
@ -70,7 +70,7 @@ func TestKeeper_Query(t *testing.T) {
// create account
sender := []byte("sender")
_, accAddr, err := m.Init(ctx, "test", sender, &types.Empty{}, nil)
_, accAddr, err := m.Init(ctx, "test", sender, &types.Empty{}, nil, nil)
require.NoError(t, err)
t.Run("ok", func(t *testing.T) {

View File

@ -24,24 +24,46 @@ func TestMsgServer(t *testing.T) {
Sender: "sender",
AccountType: "test",
Message: initMsg,
AddressSeed: []byte("seed"),
})
require.NoError(t, err)
require.NotNil(t, initResp)
// execute
executeMsg := &wrapperspb.StringValue{
Value: "10",
}
executeMsgAny, err := implementation.PackAny(executeMsg)
require.NoError(t, err)
t.Run("success", func(t *testing.T) {
// execute
executeMsg := &wrapperspb.StringValue{
Value: "10",
}
executeMsgAny, err := implementation.PackAny(executeMsg)
require.NoError(t, err)
execResp, err := s.Execute(ctx, &v1.MsgExecute{
Sender: "sender",
Target: initResp.AccountAddress,
Message: executeMsgAny,
execResp, err := s.Execute(ctx, &v1.MsgExecute{
Sender: "sender",
Target: initResp.AccountAddress,
Message: executeMsgAny,
})
require.NoError(t, err)
require.NotNil(t, execResp)
})
t.Run("fail initting same account twice", func(t *testing.T) {
_, err := s.Init(ctx, &v1.MsgInit{
Sender: "sender",
AccountType: "test",
Message: initMsg,
AddressSeed: []byte("seed"),
})
require.ErrorIs(t, err, ErrAccountAlreadyExists)
})
t.Run("initting without seed", func(t *testing.T) {
_, err := s.Init(ctx, &v1.MsgInit{
Sender: "sender",
AccountType: "test",
Message: initMsg,
})
require.NoError(t, err)
})
require.NoError(t, err)
require.NotNil(t, execResp)
}
func TestMsgServer_BundlingDisabled(t *testing.T) {

View File

@ -39,6 +39,9 @@ message MsgInit {
// send alongside the request.
repeated cosmos.base.v1beta1.Coin funds = 4
[(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", (gogoproto.nullable) = false];
// address_seed can be used to deterministically create the address of the account.
// If not present the address will be generated based on its associated account number.
bytes address_seed = 5;
}
// MsgInitResponse defines the Create response type for the Msg/Create RPC method.

View File

@ -44,6 +44,9 @@ type MsgInit struct {
// funds contains the coins that the account wants to
// send alongside the request.
Funds github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,4,rep,name=funds,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"funds"`
// address_seed can be used to deterministically create the address of the account.
// If not present the address will be generated based on its associated account number.
AddressSeed []byte `protobuf:"bytes,5,opt,name=address_seed,json=addressSeed,proto3" json:"address_seed,omitempty"`
}
func (m *MsgInit) Reset() { *m = MsgInit{} }
@ -107,6 +110,13 @@ func (m *MsgInit) GetFunds() github_com_cosmos_cosmos_sdk_types.Coins {
return nil
}
func (m *MsgInit) GetAddressSeed() []byte {
if m != nil {
return m.AddressSeed
}
return nil
}
// MsgInitResponse defines the Create response type for the Msg/Create RPC method.
type MsgInitResponse struct {
// account_address is the address of the newly created account.
@ -496,51 +506,52 @@ func init() {
func init() { proto.RegisterFile("cosmos/accounts/v1/tx.proto", fileDescriptor_29c2b6d8a13d4189) }
var fileDescriptor_29c2b6d8a13d4189 = []byte{
// 690 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0xcb, 0x4e, 0xdb, 0x4c,
0x14, 0x8e, 0x73, 0xfd, 0x39, 0xe1, 0x2f, 0x74, 0x4a, 0xc1, 0x18, 0xc9, 0xa4, 0xe9, 0x2d, 0x42,
0xd4, 0x26, 0xb4, 0x6a, 0x25, 0x76, 0x80, 0xe8, 0x45, 0x2a, 0x12, 0x8d, 0xe8, 0xa6, 0x9b, 0xc8,
0xb1, 0x07, 0x13, 0x41, 0x3c, 0x91, 0xcf, 0x18, 0x25, 0xbb, 0xaa, 0x0f, 0x50, 0xf5, 0x39, 0xba,
0xe2, 0x31, 0x58, 0xb2, 0xec, 0xa2, 0xea, 0x05, 0x2a, 0xf1, 0x1a, 0x55, 0xc6, 0x33, 0x36, 0xe1,
0x12, 0xb1, 0xec, 0x2a, 0x33, 0xf3, 0x9d, 0xf3, 0x9d, 0xf3, 0x7d, 0x27, 0x33, 0x86, 0x39, 0x97,
0x61, 0x87, 0xa1, 0xed, 0xb8, 0x2e, 0x8b, 0x02, 0x8e, 0xf6, 0x41, 0xdd, 0xe6, 0x3d, 0xab, 0x1b,
0x32, 0xce, 0x08, 0x89, 0x41, 0x4b, 0x81, 0xd6, 0x41, 0xdd, 0x98, 0xf5, 0x19, 0xf3, 0xf7, 0xa9,
0x2d, 0x22, 0x5a, 0xd1, 0x8e, 0xed, 0x04, 0xfd, 0x38, 0xdc, 0x98, 0x91, 0x5c, 0x1d, 0xf4, 0x07,
0x34, 0x1d, 0xf4, 0x25, 0x60, 0x4a, 0xa0, 0xe5, 0x20, 0xb5, 0x0f, 0xea, 0x2d, 0xca, 0x9d, 0xba,
0xed, 0xb2, 0x76, 0x20, 0x71, 0x43, 0xe2, 0xbc, 0x97, 0xa0, 0xaa, 0x07, 0x63, 0xca, 0x67, 0x3e,
0x13, 0x4b, 0x7b, 0xb0, 0x8a, 0x4f, 0xab, 0x7f, 0x34, 0x28, 0x6d, 0xa2, 0xff, 0x26, 0x68, 0x73,
0x32, 0x0d, 0x45, 0xa4, 0x81, 0x47, 0x43, 0x5d, 0xab, 0x68, 0xb5, 0xb1, 0x86, 0xdc, 0x91, 0x7b,
0x30, 0x2e, 0x1b, 0x6f, 0xf2, 0x7e, 0x97, 0xea, 0x59, 0x81, 0x96, 0xe5, 0xd9, 0x76, 0xbf, 0x4b,
0x89, 0x05, 0xa5, 0x0e, 0x45, 0x74, 0x7c, 0xaa, 0xe7, 0x2a, 0x5a, 0xad, 0xbc, 0x3c, 0x65, 0xc5,
0xf2, 0x2c, 0x25, 0xcf, 0x5a, 0x0d, 0xfa, 0x0d, 0x15, 0x44, 0x1c, 0x28, 0xec, 0x44, 0x81, 0x87,
0x7a, 0xbe, 0x92, 0xab, 0x95, 0x97, 0x67, 0x2d, 0x69, 0xd0, 0x40, 0x98, 0x25, 0x5b, 0xb7, 0xd6,
0x59, 0x3b, 0x58, 0x5b, 0x3a, 0xfa, 0x31, 0x9f, 0xf9, 0xfa, 0x73, 0xbe, 0xe6, 0xb7, 0xf9, 0x6e,
0xd4, 0xb2, 0x5c, 0xd6, 0xb1, 0xa5, 0xca, 0xf8, 0xe7, 0x09, 0x7a, 0x7b, 0xf6, 0xa0, 0x2f, 0x14,
0x09, 0xd8, 0x88, 0x99, 0x57, 0xca, 0x9f, 0xce, 0x0e, 0x17, 0xa4, 0x84, 0xea, 0x3e, 0x4c, 0x48,
0x95, 0x0d, 0x8a, 0x5d, 0x16, 0x20, 0x25, 0x8f, 0x61, 0x42, 0xa9, 0x72, 0x3c, 0x2f, 0xa4, 0x88,
0x52, 0xf6, 0x2d, 0x79, 0xbc, 0x1a, 0x9f, 0x92, 0x25, 0xf8, 0x2f, 0x94, 0x49, 0x42, 0xfa, 0x75,
0xe2, 0x92, 0xa8, 0xea, 0x77, 0x0d, 0x60, 0x13, 0xfd, 0x8d, 0x1e, 0x75, 0x23, 0x4e, 0xaf, 0xf5,
0x75, 0x1a, 0x8a, 0xdc, 0x09, 0x7d, 0xca, 0xa5, 0xa3, 0x72, 0xf7, 0xcf, 0x9b, 0xf9, 0x12, 0x48,
0xaa, 0x2e, 0xf1, 0xf3, 0xbc, 0x4d, 0xda, 0x8d, 0x6c, 0x7a, 0x0b, 0x93, 0x29, 0xcf, 0x5a, 0x14,
0x78, 0xfb, 0x94, 0xe8, 0x50, 0x6a, 0x89, 0x95, 0x32, 0x4b, 0x6d, 0xc9, 0x24, 0xe4, 0x78, 0x0f,
0xf5, 0x6c, 0x25, 0x57, 0x1b, 0x6f, 0x0c, 0x96, 0x2b, 0xe3, 0x83, 0xa6, 0x14, 0x5e, 0xfd, 0x9d,
0x85, 0xdb, 0x31, 0x89, 0xb7, 0xdd, 0x4b, 0xba, 0x7a, 0x0e, 0x33, 0x4e, 0xc4, 0x77, 0x69, 0xc0,
0xdb, 0xae, 0xc3, 0xdb, 0x2c, 0x68, 0xfa, 0x0e, 0x36, 0x23, 0xa4, 0x9e, 0xe0, 0xcf, 0x37, 0xee,
0x0e, 0xc3, 0xaf, 0x1c, 0x7c, 0x8f, 0xd4, 0x23, 0x2f, 0x40, 0x97, 0xc4, 0xcd, 0xae, 0xd3, 0xef,
0xd0, 0x80, 0xa7, 0x89, 0xd9, 0x38, 0x51, 0xe2, 0x5b, 0x31, 0xac, 0x12, 0xb7, 0x60, 0xf6, 0x62,
0xa2, 0x12, 0x8c, 0x7a, 0x4e, 0x0c, 0xe8, 0x6a, 0x5f, 0x66, 0x86, 0xf9, 0x94, 0x02, 0x24, 0x8b,
0x40, 0xa8, 0xf0, 0x68, 0xa8, 0xfb, 0xbc, 0x68, 0x62, 0x32, 0x41, 0x54, 0xfd, 0x0d, 0xb8, 0x93,
0x46, 0xa7, 0x95, 0x0b, 0x23, 0x2a, 0xa7, 0xf4, 0x69, 0xd1, 0x29, 0x28, 0xd0, 0x30, 0x64, 0xa1,
0x5e, 0x14, 0x53, 0x88, 0x37, 0xd5, 0x26, 0xe8, 0x17, 0x27, 0x96, 0x38, 0xbd, 0x0e, 0x63, 0x69,
0x39, 0x4d, 0x94, 0x7b, 0x68, 0x5d, 0x7e, 0xf7, 0xac, 0x4b, 0x33, 0x6a, 0xa4, 0x79, 0xcb, 0x9f,
0xb3, 0x90, 0xdb, 0x44, 0x9f, 0xbc, 0x86, 0xbc, 0x78, 0x92, 0xe6, 0xae, 0x62, 0x90, 0x37, 0xd9,
0xb8, 0x3f, 0x02, 0x4c, 0xda, 0x7a, 0x07, 0x25, 0x75, 0x0f, 0xcd, 0x6b, 0xe2, 0x25, 0x6e, 0x3c,
0x1a, 0x8d, 0x27, 0x94, 0x2e, 0xfc, 0x3f, 0xfc, 0xa7, 0x7d, 0x30, 0x3a, 0x31, 0x8e, 0x32, 0x16,
0x6f, 0x12, 0xa5, 0x8a, 0x18, 0x85, 0x8f, 0x67, 0x87, 0x0b, 0xda, 0xda, 0xb3, 0xa3, 0x13, 0x53,
0x3b, 0x3e, 0x31, 0xb5, 0x5f, 0x27, 0xa6, 0xf6, 0xe5, 0xd4, 0xcc, 0x1c, 0x9f, 0x9a, 0x99, 0x6f,
0xa7, 0x66, 0xe6, 0x83, 0x7c, 0xeb, 0xd1, 0xdb, 0xb3, 0xda, 0xcc, 0xee, 0x9d, 0xff, 0xf0, 0xb4,
0x8a, 0x62, 0xbe, 0x4f, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x15, 0x7e, 0x1c, 0x2a, 0x95, 0x06,
0x00, 0x00,
// 709 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0xcb, 0x4e, 0xdb, 0x40,
0x14, 0x8d, 0xf3, 0x2c, 0x37, 0x69, 0xa1, 0x53, 0x0a, 0xc6, 0x48, 0x26, 0x4d, 0x5f, 0x11, 0xa2,
0x36, 0xa1, 0x55, 0x2b, 0xb1, 0x03, 0x44, 0x1f, 0x52, 0x91, 0xa8, 0x4b, 0x37, 0xdd, 0x44, 0x8e,
0x3d, 0x98, 0x08, 0xe2, 0x89, 0x7c, 0xc7, 0x28, 0xd9, 0x55, 0xdd, 0x74, 0x57, 0xf5, 0x3b, 0xba,
0xe2, 0x33, 0x58, 0xb2, 0xec, 0xa2, 0xea, 0x03, 0x16, 0xfc, 0x46, 0x95, 0xf1, 0xd8, 0x26, 0x3c,
0x22, 0x96, 0x5d, 0x65, 0x66, 0xce, 0xbd, 0xe7, 0x9e, 0x73, 0x26, 0xb6, 0x61, 0xd6, 0x61, 0xd8,
0x61, 0x68, 0xda, 0x8e, 0xc3, 0x42, 0x9f, 0xa3, 0xb9, 0xdf, 0x30, 0x79, 0xcf, 0xe8, 0x06, 0x8c,
0x33, 0x42, 0x22, 0xd0, 0x88, 0x41, 0x63, 0xbf, 0xa1, 0xcd, 0x78, 0x8c, 0x79, 0x7b, 0xd4, 0x14,
0x15, 0xad, 0x70, 0xdb, 0xb4, 0xfd, 0x7e, 0x54, 0xae, 0x4d, 0x4b, 0xae, 0x0e, 0x7a, 0x03, 0x9a,
0x0e, 0x7a, 0x12, 0xd0, 0x25, 0xd0, 0xb2, 0x91, 0x9a, 0xfb, 0x8d, 0x16, 0xe5, 0x76, 0xc3, 0x74,
0x58, 0xdb, 0x97, 0xb8, 0x26, 0x71, 0xde, 0x4b, 0xd0, 0x58, 0x83, 0x36, 0xe9, 0x31, 0x8f, 0x89,
0xa5, 0x39, 0x58, 0x45, 0xa7, 0xb5, 0x2f, 0x59, 0x28, 0x6d, 0xa0, 0xf7, 0xc6, 0x6f, 0x73, 0x32,
0x05, 0x45, 0xa4, 0xbe, 0x4b, 0x03, 0x55, 0xa9, 0x2a, 0xf5, 0x31, 0x4b, 0xee, 0xc8, 0x3d, 0xa8,
0x48, 0xe1, 0x4d, 0xde, 0xef, 0x52, 0x35, 0x2b, 0xd0, 0xb2, 0x3c, 0xdb, 0xea, 0x77, 0x29, 0x31,
0xa0, 0xd4, 0xa1, 0x88, 0xb6, 0x47, 0xd5, 0x5c, 0x55, 0xa9, 0x97, 0x97, 0x26, 0x8d, 0xc8, 0x9e,
0x11, 0xdb, 0x33, 0x56, 0xfc, 0xbe, 0x15, 0x17, 0x11, 0x1b, 0x0a, 0xdb, 0xa1, 0xef, 0xa2, 0x9a,
0xaf, 0xe6, 0xea, 0xe5, 0xa5, 0x19, 0x43, 0x06, 0x34, 0x30, 0x66, 0x48, 0xe9, 0xc6, 0x1a, 0x6b,
0xfb, 0xab, 0x8b, 0x87, 0xbf, 0xe6, 0x32, 0xdf, 0x7f, 0xcf, 0xd5, 0xbd, 0x36, 0xdf, 0x09, 0x5b,
0x86, 0xc3, 0x3a, 0xa6, 0x74, 0x19, 0xfd, 0x3c, 0x41, 0x77, 0xd7, 0x1c, 0xe8, 0x42, 0xd1, 0x80,
0x56, 0xc4, 0x2c, 0x54, 0xbb, 0x6e, 0x40, 0x11, 0x9b, 0x48, 0xa9, 0xab, 0x16, 0xaa, 0x4a, 0xbd,
0x62, 0x95, 0xe5, 0xd9, 0x7b, 0x4a, 0xdd, 0xe5, 0xf2, 0xe7, 0xd3, 0x83, 0x79, 0xe9, 0xb2, 0xb6,
0x07, 0xe3, 0x32, 0x08, 0x8b, 0x62, 0x97, 0xf9, 0x48, 0xc9, 0x63, 0x18, 0x8f, 0x8d, 0xcb, 0x36,
0x99, 0xcc, 0x2d, 0x79, 0xbc, 0x12, 0x9d, 0x92, 0x45, 0xb8, 0x11, 0xc8, 0x26, 0x91, 0xce, 0x55,
0xfe, 0x93, 0xaa, 0xda, 0x4f, 0x05, 0x60, 0x03, 0xbd, 0xf5, 0x1e, 0x75, 0x42, 0x4e, 0xaf, 0x8c,
0x7e, 0x0a, 0x8a, 0xdc, 0x0e, 0x3c, 0xca, 0x65, 0xe8, 0x72, 0xf7, 0x1f, 0xe6, 0x3d, 0x1c, 0xe6,
0x4b, 0x20, 0xa9, 0xbb, 0x24, 0xcf, 0xb3, 0x31, 0x29, 0xd7, 0x8a, 0xe9, 0x2d, 0x4c, 0xa4, 0x3c,
0xab, 0xa1, 0xef, 0xee, 0x51, 0xa2, 0x42, 0xa9, 0x25, 0x56, 0x71, 0x58, 0xf1, 0x96, 0x4c, 0x40,
0x8e, 0xf7, 0x50, 0xcd, 0x56, 0x73, 0xf5, 0x8a, 0x35, 0x58, 0x2e, 0x57, 0x06, 0xa2, 0x62, 0xbc,
0xf6, 0x37, 0x0b, 0xb7, 0x23, 0x12, 0x77, 0xab, 0x97, 0xa8, 0x7a, 0x0e, 0xd3, 0x76, 0xc8, 0x77,
0xa8, 0xcf, 0xdb, 0x8e, 0xcd, 0xdb, 0xcc, 0x6f, 0x7a, 0x36, 0x36, 0x43, 0xa4, 0xae, 0xe0, 0xcf,
0x5b, 0x77, 0x87, 0xe1, 0x57, 0x36, 0x7e, 0x40, 0xea, 0x92, 0x17, 0xa0, 0x4a, 0xe2, 0x66, 0xd7,
0xee, 0x77, 0xa8, 0xcf, 0xd3, 0xc6, 0x6c, 0xd4, 0x28, 0xf1, 0xcd, 0x08, 0x8e, 0x1b, 0x37, 0x61,
0xe6, 0x7c, 0x63, 0x6c, 0x18, 0xd5, 0x9c, 0xb8, 0xa0, 0xcb, 0x73, 0x99, 0x1e, 0xe6, 0x8b, 0x1d,
0x20, 0x59, 0x00, 0x42, 0x45, 0x46, 0x43, 0xea, 0xf3, 0x42, 0xc4, 0x44, 0x82, 0xc4, 0xf3, 0xd7,
0xe1, 0x4e, 0x5a, 0x9d, 0x4e, 0x2e, 0x8c, 0x98, 0x9c, 0xd2, 0xa7, 0x43, 0x27, 0xa1, 0x40, 0x83,
0x80, 0x05, 0x6a, 0x51, 0xdc, 0x42, 0xb4, 0xa9, 0x35, 0x41, 0x3d, 0x7f, 0x63, 0x49, 0xd2, 0x6b,
0x30, 0x96, 0x8e, 0x53, 0xc4, 0xb8, 0x87, 0xc6, 0xc5, 0x57, 0xa3, 0x71, 0xe1, 0x8e, 0xac, 0xb4,
0x6f, 0xe9, 0x6b, 0x16, 0x72, 0x1b, 0xe8, 0x91, 0xd7, 0x90, 0x17, 0x6f, 0xad, 0xd9, 0xcb, 0x18,
0xe4, 0x93, 0xac, 0xdd, 0x1f, 0x01, 0x26, 0xb2, 0xde, 0x41, 0x29, 0x7e, 0x0e, 0xf5, 0x2b, 0xea,
0x25, 0xae, 0x3d, 0x1a, 0x8d, 0x27, 0x94, 0x0e, 0xdc, 0x1c, 0xfe, 0xd3, 0x3e, 0x18, 0xdd, 0x18,
0x55, 0x69, 0x0b, 0xd7, 0xa9, 0x8a, 0x87, 0x68, 0x85, 0x4f, 0xa7, 0x07, 0xf3, 0xca, 0xea, 0xb3,
0xc3, 0x63, 0x5d, 0x39, 0x3a, 0xd6, 0x95, 0x3f, 0xc7, 0xba, 0xf2, 0xed, 0x44, 0xcf, 0x1c, 0x9d,
0xe8, 0x99, 0x1f, 0x27, 0x7a, 0xe6, 0xa3, 0xfc, 0x1c, 0xa0, 0xbb, 0x6b, 0xb4, 0x99, 0xd9, 0x3b,
0xfb, 0x6d, 0x6a, 0x15, 0xc5, 0xfd, 0x3e, 0xfd, 0x17, 0x00, 0x00, 0xff, 0xff, 0x53, 0x6a, 0x24,
0xdc, 0xb8, 0x06, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -724,6 +735,13 @@ func (m *MsgInit) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if len(m.AddressSeed) > 0 {
i -= len(m.AddressSeed)
copy(dAtA[i:], m.AddressSeed)
i = encodeVarintTx(dAtA, i, uint64(len(m.AddressSeed)))
i--
dAtA[i] = 0x2a
}
if len(m.Funds) > 0 {
for iNdEx := len(m.Funds) - 1; iNdEx >= 0; iNdEx-- {
{
@ -1091,6 +1109,10 @@ func (m *MsgInit) Size() (n int) {
n += 1 + l + sovTx(uint64(l))
}
}
l = len(m.AddressSeed)
if l > 0 {
n += 1 + l + sovTx(uint64(l))
}
return n
}
@ -1388,6 +1410,40 @@ func (m *MsgInit) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 5:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field AddressSeed", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthTx
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthTx
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.AddressSeed = append(m.AddressSeed[:0], dAtA[iNdEx:postIndex]...)
if m.AddressSeed == nil {
m.AddressSeed = []byte{}
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipTx(dAtA[iNdEx:])