Skip to content

Commit

Permalink
Merge branch 'cosmos:main' into fix-broken-links
Browse files Browse the repository at this point in the history
  • Loading branch information
MasterPi-2124 committed Apr 29, 2024
2 parents 1ad41a6 + 84712ed commit 5cdc741
Show file tree
Hide file tree
Showing 5 changed files with 308 additions and 22 deletions.
2 changes: 1 addition & 1 deletion baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ func (app *BaseApp) setTrace(trace bool) {
}

func (app *BaseApp) setIndexEvents(ie []string) {
app.indexEvents = make(map[string]struct{})
app.indexEvents = make(map[string]struct{}, len(ie))

for _, e := range ie {
app.indexEvents[e] = struct{}{}
Expand Down
52 changes: 37 additions & 15 deletions store/snapshots/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ func TestStore_Prune(t *testing.T) {
}

func TestStore_Save(t *testing.T) {
t.Parallel()
store := setupStore(t)
// Saving a snapshot should work
snapshot, err := store.Save(4, 1, makeChunks([][]byte{{1}, {2}}))
Expand Down Expand Up @@ -318,19 +319,40 @@ func TestStore_Save(t *testing.T) {

// Saving a snapshot should error if a snapshot is already in progress for the same height,
// regardless of format. However, a different height should succeed.
ch = make(chan io.ReadCloser)
mtx := sync.Mutex{}
mtx.Lock()
go func() {
mtx.Unlock()
_, err := store.Save(7, 1, ch)
require.NoError(t, err)
}()
mtx.Lock()
defer mtx.Unlock()
_, err = store.Save(7, 2, makeChunks(nil))
require.Error(t, err)
_, err = store.Save(8, 1, makeChunks(nil))
require.NoError(t, err)
close(ch)
var (
wgStart, wgDone sync.WaitGroup
mu sync.Mutex
gotErrHeights []uint64
)
srcHeights := []uint64{7, 7, 7, 8, 9}
wgStart.Add(len(srcHeights))
wgDone.Add(len(srcHeights))
for _, h := range srcHeights {
ch = make(chan io.ReadCloser, 1)
ch <- &ReadCloserMock{} // does not block on a buffered channel
close(ch)
go func(height uint64) {
wgStart.Done()
wgStart.Wait() // wait for all routines started
if _, err = store.Save(height, 1, ch); err != nil {
mu.Lock()
gotErrHeights = append(gotErrHeights, height)
mu.Unlock()
}
wgDone.Done()
}(h)
}
wgDone.Wait() // wait for all routines completed
assert.Equal(t, []uint64{7, 7}, gotErrHeights)
}

type ReadCloserMock struct {
}

func (r ReadCloserMock) Read(p []byte) (n int, err error) {
return len(p), io.EOF
}

func (r ReadCloserMock) Close() error {
return nil
}
259 changes: 256 additions & 3 deletions x/accounts/defaults/lockup/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,258 @@
# x/accounts/lockup
# Lockup Accounts

<!--- TODO: need to expand more on this --->

The x/accounts/lockup module provides the implementation for lockup accounts within the x/accounts module.
* [Lockup Account Types](#lockup-account-types)
* [BaseLockup](#baselockup)
* [ContinuousLockup](#continuouslockup)
* [DelayedLockup](#delayedlockup)
* [PeriodicLockup](#periodiclockup)
* [PermanentLocked](#permanentlocked)
* [Genesis Initialization](#genesis-initialization)
* [Examples](#examples)
* [Simple](#simple)
* [Slashing](#slashing)
* [Periodic Lockup](#periodic-lockup)

The x/accounts/defaults/lockup module provides the implementation for lockup accounts within the x/accounts module.

## Lockup Account Types

### BaseLockup

The base lockup account is used by all default lockup accounts. It contains the basic information for a lockup account. The Base lockup account keeps knowledge of the staking delegations from the account.

```go
type BaseLockup struct {
// Owner is the address of the account owner.
Owner collections.Item[[]byte]
OriginalLocking collections.Map[string, math.Int]
DelegatedFree collections.Map[string, math.Int]
DelegatedLocking collections.Map[string, math.Int]
WithdrawedCoins collections.Map[string, math.Int]
addressCodec address.Codec
headerService header.Service
// lockup end time.
EndTime collections.Item[time.Time]
}
```

### ContinuousLockup

The continuous lockup account has a future start time and begins unlocking continuously until the specified end date.

To determine the amount of coins that are vested for a given block time `T`, the
following is performed:

1. Compute `X := T - StartTime`
2. Compute `Y := EndTime - StartTime`
3. Compute `V' := OV * (X / Y)`
4. Compute `V := OV - V'`

Thus, the total amount of _vested_ coins is `V'` and the remaining amount, `V`,
is _lockup_.

```go
type ContinuousLockingAccount struct {
*BaseLockup
StartTime collections.Item[time.Time]
}
```

### DelayedLockup

The delayed lockup account unlocks all tokens at a specific time. The account can receive coins and send coins. The account can be used to lock coins for a long period of time.

```go
type DelayedLockingAccount struct {
*BaseLockup
}
```

### PeriodicLockup

The periodic lockup account locks tokens for a series of periods. The account can receive coins and send coins. After all the periods, all the coins are unlocked and the account can send coins.

Periodic lockup accounts require calculating the coins released during each period for a given block time `T`. Note that multiple periods could have passed when calling `GetVestedCoins`, so we must iterate over each period until the end of that period is after `T`.

1. Set `CT := StartTime`
2. Set `V' := 0`

For each Period P:

1. Compute `X := T - CT`
2. IF `X >= P.Length`
1. Compute `V' += P.Amount`
2. Compute `CT += P.Length`
3. ELSE break
3. Compute `V := OV - V'`

```go
type PeriodicLockingAccount struct {
*BaseLockup
StartTime collections.Item[time.Time]
LockingPeriods collections.Vec[lockuptypes.Period]
}
```

### PermanentLocked

The permanent lockup account permanently locks the coins in the account. The account can only receive coins and cannot send coins. The account can be used to lock coins for a long period of time.

```go
type PermanentLockingAccount struct {
*BaseLockup
}
```

## Genesis Initialization

<!-- TODO: once implemented -->

## Examples

### Simple

Given a continuous lockup account with 10 vested coins.

```text
OV = 10
DF = 0
DV = 0
BC = 10
V = 10
V' = 0
```

1. Immediately receives 1 coin

```text
BC = 11
```

2. Time passes, 2 coins vest

```text
V = 8
V' = 2
```

3. Delegates 4 coins to validator A

```text
DV = 4
BC = 7
```

4. Sends 3 coins

```text
BC = 4
```

5. More time passes, 2 more coins vest

```text
V = 6
V' = 4
```

6. Sends 2 coins. At this point, the account cannot send anymore until further
coins vest or it receives additional coins. It can still, however, delegate.

```text
BC = 2
```

### Slashing

Same initial starting conditions as the simple example.

1. Time passes, 5 coins vest

```text
V = 5
V' = 5
```

2. Delegate 5 coins to validator A

```text
DV = 5
BC = 5
```

3. Delegate 5 coins to validator B

```text
DF = 5
BC = 0
```

4. Validator A gets slashed by 50%, making the delegation to A now worth 2.5 coins
5. Undelegate from validator A (2.5 coins)

```text
DF = 5 - 2.5 = 2.5
BC = 0 + 2.5 = 2.5
```

6. Undelegate from validator B (5 coins). The account at this point can only
send 2.5 coins unless it receives more coins or until more coins vest.
It can still, however, delegate.

```text
DV = 5 - 2.5 = 2.5
DF = 2.5 - 2.5 = 0
BC = 2.5 + 5 = 7.5
```

Notice how we have an excess amount of `DV`.

### Periodic Lockup

A lockup account is created where 100 tokens will be released over 1 year, with
1/4 of tokens vesting each quarter. The lockup schedule would be as follows:

```yaml
Periods:
- amount: 25stake, length: 7884000
- amount: 25stake, length: 7884000
- amount: 25stake, length: 7884000
- amount: 25stake, length: 7884000
```

```text
OV = 100
DF = 0
DV = 0
BC = 100
V = 100
V' = 0
```

1. Immediately receives 1 coin

```text
BC = 101
```

2. Lockup period 1 passes, 25 coins vest

```text
V = 75
V' = 25
```

3. During lockup period 2, 5 coins are transferred and 5 coins are delegated

```text
DV = 5
BC = 91
```

4. Lockup period 2 passes, 25 coins vest

```text
V = 50
V' = 50
```
11 changes: 11 additions & 0 deletions x/accounts/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,17 @@ func (k Keeper) sendAnyMessages(ctx context.Context, sender []byte, anyMessages
// SendModuleMessageUntyped can be used to send a message towards a module.
// It should be used when the response type is not known by the caller.
func (k Keeper) SendModuleMessageUntyped(ctx context.Context, sender []byte, msg implementation.ProtoMsg) (implementation.ProtoMsg, error) {
// do sender assertions.
wantSenders, _, err := k.codec.GetMsgV1Signers(msg)
if err != nil {
return nil, fmt.Errorf("cannot get signers: %w", err)
}
if len(wantSenders) != 1 {
return nil, fmt.Errorf("expected only one signer, got %d", len(wantSenders))
}
if !bytes.Equal(sender, wantSenders[0]) {
return nil, fmt.Errorf("%w: sender does not match expected sender", ErrUnauthorized)
}
resp, err := k.RouterService.MessageRouterService().InvokeUntyped(ctx, msg)
if err != nil {
return nil, err
Expand Down
6 changes: 3 additions & 3 deletions x/circuit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Reset is called by an authorized account to enable execution for a specific msgU
### MsgAuthorizeCircuitBreaker

```protobuf reference
https://github.com/cosmos/cosmos-sdk/blob/main/proto/cosmos/circuit/v1/tx.proto#L25-L75
https://github.com/cosmos/cosmos-sdk/blob/main/x/circuit/proto/cosmos/circuit/v1/tx.proto#L25-L40
```

This message is expected to fail if:
Expand All @@ -111,7 +111,7 @@ This message is expected to fail if:
### MsgTripCircuitBreaker

```protobuf reference
https://github.com/cosmos/cosmos-sdk/blob/main/proto/cosmos/circuit/v1/tx.proto#L77-L93
https://github.com/cosmos/cosmos-sdk/blob/main/x/circuit/proto/cosmos/circuit/v1/tx.proto#L47-L60
```

This message is expected to fail if:
Expand All @@ -121,7 +121,7 @@ This message is expected to fail if:
### MsgResetCircuitBreaker

```protobuf reference
https://github.com/cosmos/cosmos-sdk/blob/main/proto/cosmos/circuit/v1/tx.proto#L95-109
https://github.com/cosmos/cosmos-sdk/blob/main/x/circuit/proto/cosmos/circuit/v1/tx.proto#L67-L78
```

This message is expected to fail if:
Expand Down

0 comments on commit 5cdc741

Please sign in to comment.