Skip to content

Commit

Permalink
Merge branch 'master' into bez/5913-remove-supply-mod
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderbez committed Apr 17, 2020
2 parents 124d689 + de00a7f commit 3324a00
Show file tree
Hide file tree
Showing 35 changed files with 2,003 additions and 590 deletions.
16 changes: 12 additions & 4 deletions .github/workflows/sims.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ jobs:
build:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, 'skip-sims')"
steps:
- uses: actions/setup-go@v2-beta
- uses: actions/checkout@v2
- run: |
make build
install-runsim:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/setup-go@v2-beta
- name: install runsim
Expand All @@ -24,7 +32,7 @@ jobs:

test-sim-nondeterminism:
runs-on: ubuntu-latest
needs: Build
needs: [build, install-runsim]
steps:
- uses: actions/setup-go@v2-beta
- uses: actions/checkout@v2
Expand All @@ -38,7 +46,7 @@ jobs:
test-sim-import-export:
runs-on: ubuntu-latest
needs: Build
needs: [build, install-runsim]
steps:
- uses: actions/setup-go@v2-beta
- uses: actions/checkout@v2
Expand All @@ -52,7 +60,7 @@ jobs:
test-sim-after-import:
runs-on: ubuntu-latest
needs: Build
needs: [build, install-runsim]
steps:
- uses: actions/setup-go@v2-beta
- uses: actions/checkout@v2
Expand All @@ -66,7 +74,7 @@ jobs:
test-sim-multi-seed-short:
runs-on: ubuntu-latest
needs: Build
needs: [build, install-runsim]
steps:
- uses: actions/setup-go@v2-beta
- uses: actions/checkout@v2
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ jobs:
steps:
- uses: actions/setup-go@v2-beta
- uses: actions/checkout@v2
- name: build
run: |
make build
- name: test & coverage report creation
run: |
go test ./... -mod=readonly -timeout 12m -race -coverprofile=coverage.txt -covermode=atomic -tags='ledger test_ledger_mock'
Expand Down
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,9 @@ information on how to implement the new `Keyring` interface.
* [ICS 020 - Fungible Token Transfer](https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer) module
* [ICS 023 - Vector Commitments](https://github.com/cosmos/ics/tree/master/spec/ics-023-vector-commitments) subpackage
* (ibc/ante) Implement IBC `AnteHandler` as per [ADR 15 - IBC Packet Receiver](https://github.com/cosmos/tree/master/docs/architecture/adr-015-ibc-packet-receiver.md).
* (x/capability) [\#5828](https://github.com/cosmos/cosmos-sdk/pull/5828) Capability module integration as outlined in [ADR 3 - Dynamic Capability Store](https://github.com/cosmos/tree/master/docs/architecture/adr-003-dynamic-capability-store.md).
* (x/params) [\#6005](https://github.com/cosmos/cosmos-sdk/pull/6005) Add new CLI command for querying raw x/params parameters by subspace and key.
* (x/capability) [\#5828](https://github.com/cosmos/cosmos-sdk/pull/5828) Capability module integration as outlined in [ADR 3 - Dynamic Capability Store](https://github.com/cosmos/tree/master/docs/architecture/adr-003-dynamic-capability-store.md).
* (x/params) [\#6005](https://github.com/cosmos/cosmos-sdk/pull/6005) Add new CLI command for querying raw x/params parameters by subspace and key.
* (x/ibc) [\#5769] Implementation of localhost client.

### Bug Fixes

Expand Down
101 changes: 56 additions & 45 deletions docs/architecture/adr-003-dynamic-capability-store.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ At present, the Cosmos SDK does not have the ability to do this. Object-capabili
and passed to Keepers as fixed arguments ([example](https://github.com/cosmos/gaia/blob/dcbddd9f04b3086c0ad07ee65de16e7adedc7da4/app/app.go#L160)). Keepers cannot create or store capability keys during transaction execution — although they could call `NewKVStoreKey` and take the memory address
of the returned struct, storing this in the Merklised store would result in a consensus fault, since the memory address will be different on each machine (this is intentional — were this not the case, the keys would be predictable and couldn't serve as object capabilities).

Keepers need a way to keep a private map of store keys which can be altered during transaction execution, along with a suitable mechanism for regenerating the unique memory addresses (capability keys) in this map whenever the application is started or restarted.
Keepers need a way to keep a private map of store keys which can be altered during transaction execution, along with a suitable mechanism for regenerating the unique memory addresses (capability keys) in this map whenever the application is started or restarted, along with a mechanism to revert capability creation on tx failure.
This ADR proposes such an interface & mechanism.

## Decision
Expand All @@ -32,30 +32,24 @@ new capability keys for all previously allocated capability identifiers (allocat
past transactions and assigned to particular modes), and keep them in a memory-only store while the
chain is running.

The `CapabilityKeeper` will include an ephemeral in-memory `CapabilityStore`, which internally maintains
two maps, one for forward mappings that map from module name, capability tuples to capability names and
one for reverse mappings that map from module name, capability name to capabilities. The reverse
mapping contains the actual capability objects by reference.
The `CapabilityKeeper` will include a persistent `KVStore`, a `MemoryStore`, and an in-memory map.
The persistent `KVStore` tracks which capability is owned by which modules.
The `MemoryStore` stores a forward mapping that map from module name, capability tuples to capability names and
a reverse mapping that map from module name, capability name to the capability index.
Since we cannot marshal the capability into a `KVStore` and unmarshal without changing the memory location of the capability,
the reverse mapping in the KVStore will simply map to an index. This index can then be used as a key in the ephemeral
go-map to retrieve the capability at the original memory location.

In addition to the `CapabilityStore`, the `CapabilityKeeper` will use a persistent `KVStore`, which
will track what capabilities have been created by each module. The `CapabilityKeeper` will define the
following types & functions:
The `CapabilityKeeper` will define the following types & functions:

The `Capability` interface is similar to `StoreKey`, but has a globally unique `Index()` instead of
The `Capability` is similar to `StoreKey`, but has a globally unique `Index()` instead of
a name. A `String()` method is provided for debugging.

```golang
type Capability interface {
Index() uint64
String() string
}
```

A `CapabilityKey` is simply a struct, the address of which is taken for the actual capability.
A `Capability` is simply a struct, the address of which is taken for the actual capability.

```golang
type CapabilityKey struct {
name string
type Capability struct {
index uint64
}
```

Expand All @@ -64,7 +58,8 @@ A `CapabilityKeeper` contains a persistent store key, memory store key, and mapp
```golang
type CapabilityKeeper struct {
persistentKey StoreKey
capStore CapabilityStore
memKey StoreKey
capMap map[uint64]*Capability
moduleNames map[string]interface{}
sealed bool
}
Expand All @@ -79,7 +74,8 @@ passed by other modules.
```golang
type ScopedCapabilityKeeper struct {
persistentKey StoreKey
capStore CapabilityStore
memKey StoreKey
capMap map[uint64]*Capability
moduleName string
}
```
Expand All @@ -89,20 +85,23 @@ It MUST be called before `InitialiseAndSeal`.

```golang
func (ck CapabilityKeeper) ScopeToModule(moduleName string) ScopedCapabilityKeeper {
if ck.sealed {
panic("capability keeper is sealed")
}
if _, present := ck.moduleNames[moduleName]; present {
panic("cannot create multiple scoped capability keepers for the same module name")
}

ck.moduleNames[moduleName] = struct{}{}

return ScopedCapabilityKeeper{
persistentKey: ck.persistentKey,
capStore: ck.capStore,
moduleName: moduleName,
}
if k.sealed {
panic("cannot scope to module via a sealed capability keeper")
}

if _, ok := k.scopedModules[moduleName]; ok {
panic(fmt.Sprintf("cannot create multiple scoped keepers for the same module name: %s", moduleName))
}

k.scopedModules[moduleName] = struct{}{}

return ScopedKeeper{
cdc: k.cdc,
storeKey: k.storeKey,
memKey: k.memKey,
capMap: k.capMap,
module: moduleName,
}
}
```

Expand All @@ -118,15 +117,18 @@ func (ck CapabilityKeeper) InitialiseAndSeal(ctx Context) {
}

persistentStore := ctx.KVStore(ck.persistentKey)
map := ctx.KVStore(ck.memKey)

// initialise memory store for all names in persistent store
for index, value := range persistentStore.Iter() {
capability = &CapabilityKey{index: index}

for moduleAndCapability := range value {
moduleName, capabilityName := moduleAndCapability.Split("/")
capStore.Set(moduleName + "/fwd/" + capability, capabilityName)
capStore.Set(moduleName + "/rev/" + capabilityName, capability)
memStore.Set(moduleName + "/fwd/" + capability, capabilityName)
memStore.Set(moduleName + "/rev/" + capabilityName, index)

ck.capMap[index] = capability
}
}

Expand Down Expand Up @@ -159,10 +161,13 @@ func (sck ScopedCapabilityKeeper) NewCapability(ctx Context, name string) (Capab
persistentStore.Set("index", index)

// set forward mapping in memory store from capability to name
capStore.Set(sck.moduleName + "/fwd/" + capability, name)
memStore.Set(sck.moduleName + "/fwd/" + capability, name)

// set reverse mapping in memory store from name to capability
capStore.Set(sck.moduleName + "/rev/" + name, capability)
// set reverse mapping in memory store from name to index
memStore.Set(sck.moduleName + "/rev/" + name, index)

// set the in-memory mapping from index to capability pointer
capMap[index] = capability

// return the newly created capability
return capability
Expand All @@ -176,7 +181,7 @@ with which the calling module previously associated it.
```golang
func (sck ScopedCapabilityKeeper) AuthenticateCapability(name string, capability Capability) bool {
// return whether forward mapping in memory store matches name
return capStore.Get(sck.moduleName + "/fwd/" + capability) === name
return memStore.Get(sck.moduleName + "/fwd/" + capability) === name
}
```

Expand All @@ -192,10 +197,10 @@ func (sck ScopedCapabilityKeeper) ClaimCapability(ctx Context, capability Capabi
persistentStore := ctx.KVStore(sck.persistentKey)

// set forward mapping in memory store from capability to name
capStore.Set(sck.moduleName + "/fwd/" + capability, name)
memStore.Set(sck.moduleName + "/fwd/" + capability, name)

// set reverse mapping in memory store from name to capability
capStore.Set(sck.moduleName + "/rev/" + name, capability)
memStore.Set(sck.moduleName + "/rev/" + name, capability)

// update owner set in persistent store
owners := persistentStore.Get(capability.Index())
Expand All @@ -209,8 +214,11 @@ The module is not allowed to retrieve capabilities which it does not own.

```golang
func (sck ScopedCapabilityKeeper) GetCapability(ctx Context, name string) (Capability, error) {
// fetch capability from memory store
capability := capStore.Get(sck.moduleName + "/rev/" + name)
// fetch the index of capability using reverse mapping in memstore
index := memStore.Get(sck.moduleName + "/rev/" + name)

// fetch capability from go-map using index
capability := capMap[index]

// return the capability
return capability
Expand Down Expand Up @@ -244,6 +252,7 @@ func (sck ScopedCapabilityKeeper) ReleaseCapability(ctx Context, capability Capa
} else {
// no more owners, delete the capability
persistentStore.Delete(capability.Index())
delete(capMap[capability.Index()])
}
}
```
Expand Down Expand Up @@ -318,11 +327,13 @@ Proposed.
### Positive

- Dynamic capability support.
- Allows CapabilityKeeper to return same capability pointer from go-map while reverting any writes to the persistent `KVStore` and in-memory `MemoryStore` on tx failure.

### Negative

- Requires an additional keeper.
- Some overlap with existing `StoreKey` system (in the future they could be combined, since this is a superset functionality-wise).
- Requires an extra level of indirection in the reverse mapping, since MemoryStore must map to index which must then be used as key in a go map to retrieve the actual capability

### Neutral

Expand Down
4 changes: 2 additions & 2 deletions docs/core/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Events are returned to the underlying consensus engine in the response of the fo
- [`DeliverTx`](./baseapp.md#delivertx)

Events, the `type` and `attributes`, are defined on a **per-module basis** in the module's
`/internal/types/events.go` file, and triggered from the module's [`handler`](../building-modules/handler.md)
`/types/events.go` file, and triggered from the module's [`handler`](../building-modules/handler.md)
via the [`EventManager`](#eventmanager). In addition, each module documents its events under
`spec/xx_events.md`.

Expand Down Expand Up @@ -96,7 +96,7 @@ The main `eventCategory` you can subscribe to are:
These events are triggered from the `state` package after a block is committed. You can get the
full list of `event` categories [here](https://godoc.org/github.com/tendermint/tendermint/types#pkg-constants).
The `type` and `attribute` value of the `query` allow you to filter the specific `event` you are looking for. For example, a `transfer` transaction triggers an `event` of type `Transfer` and has `Recipient` and `Sender` as `attributes` (as defined in the [`events` file of the `bank` module](https://github.com/cosmos/cosmos-sdk/blob/master/x/bank/internal/types/events.go)). Subscribing to this `event` would be done like so:
The `type` and `attribute` value of the `query` allow you to filter the specific `event` you are looking for. For example, a `transfer` transaction triggers an `event` of type `Transfer` and has `Recipient` and `Sender` as `attributes` (as defined in the [`events` file of the `bank` module](https://github.com/cosmos/cosmos-sdk/blob/master/x/bank/types/events.go)). Subscribing to this `event` would be done like so:
```json
{
Expand Down
Loading

0 comments on commit 3324a00

Please sign in to comment.