Skip to content

Commit

Permalink
#43 Simplest Rank
Browse files Browse the repository at this point in the history
  • Loading branch information
hleb-albau committed Oct 3, 2018
1 parent 7534013 commit 4267153
Show file tree
Hide file tree
Showing 9 changed files with 539 additions and 32 deletions.
53 changes: 49 additions & 4 deletions cosmos/poc/app/app.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package app

import (
"crypto/sha256"
"encoding/binary"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
. "github.com/cybercongress/cyberd/cosmos/poc/app/bank"
"github.com/cybercongress/cyberd/cosmos/poc/app/rank"
. "github.com/cybercongress/cyberd/cosmos/poc/app/storage"
abci "github.com/tendermint/tendermint/abci/types"
cmn "github.com/tendermint/tendermint/libs/common"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
"math"
)

const (
Expand Down Expand Up @@ -40,13 +44,16 @@ type CyberdApp struct {
dbKeys CyberdAppDbKeys

// manage getting and setting accounts
mainStorage MainStorage
accStorage auth.AccountMapper
feeCollectionKeeper auth.FeeCollectionKeeper
coinKeeper bank.Keeper

// cyberd storages
persistStorages CyberdPersistentStorages
memStorage *InMemoryStorage

latestRankHash []byte
}

// NewBasecoinApp returns a reference to a new CyberdApp given a
Expand All @@ -67,11 +74,11 @@ func NewCyberdApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*baseapp.
rank: sdk.NewKVStoreKey("rank"),
}

cis := NewCidIndexStorage(dbKeys.main, dbKeys.cidIndex)
ms := NewMainStorage(dbKeys.main)
storages := CyberdPersistentStorages{
CidIndex: cis,
CidIndex: NewCidIndexStorage(ms, dbKeys.cidIndex),
Links: NewLinksStorage(dbKeys.links, cdc),
Rank: NewRankStorage(cis, dbKeys.rank),
Rank: NewRankStorage(ms, dbKeys.rank),
}

// create your application type
Expand All @@ -80,6 +87,7 @@ func NewCyberdApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*baseapp.
BaseApp: baseapp.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...),
dbKeys: dbKeys,
persistStorages: storages,
mainStorage: ms,
}

// define and attach the mappers and keepers
Expand All @@ -104,7 +112,9 @@ func NewCyberdApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*baseapp.
if err != nil {
cmn.Exit(err.Error())
}
app.memStorage.Load(app.BaseApp.NewContext(true, abci.Header{}), storages, app.accStorage)
ctx := app.BaseApp.NewContext(true, abci.Header{})
app.memStorage.Load(ctx, storages, app.accStorage)
app.latestRankHash = ms.GetAppHash(ctx)

app.Seal()
return app
Expand All @@ -120,5 +130,40 @@ func (app *CyberdApp) BeginBlocker(_ sdk.Context, _ abci.RequestBeginBlock) abci
// Calculated app state will be included in N+1 block header, thus influence on block hash.
// App state is consensus driven state.
func (app *CyberdApp) EndBlocker(ctx sdk.Context, _ abci.RequestEndBlock) abci.ResponseEndBlock {

newRank := rank.CalculateRank(app.memStorage)
rankAsBytes := make([]byte, 8*len(newRank))
for i, f64 := range newRank {
binary.LittleEndian.PutUint64(rankAsBytes[i*8:i*8+8], math.Float64bits(f64))
}

hash := sha256.Sum256(rankAsBytes)
app.latestRankHash = hash[:]
app.memStorage.UpdateRank(newRank)
app.mainStorage.StoreAppHash(ctx, hash[:])
return abci.ResponseEndBlock{}
}

// Implements ABCI
func (app *CyberdApp) Commit() (res abci.ResponseCommit) {
app.BaseApp.Commit()
return abci.ResponseCommit{Data: app.latestRankHash}
}

// Implements ABCI
func (app *CyberdApp) Info(req abci.RequestInfo) abci.ResponseInfo {

if app.LastBlockHeight() == 0 {
return abci.ResponseInfo{
Data: app.BaseApp.Name(),
LastBlockHeight: app.LastBlockHeight(),
LastBlockAppHash: make([]byte, 0),
}
}

return abci.ResponseInfo{
Data: app.BaseApp.Name(),
LastBlockHeight: app.LastBlockHeight(),
LastBlockAppHash: app.latestRankHash,
}
}
1 change: 1 addition & 0 deletions cosmos/poc/app/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func GetCidNumberFunc(cis CidIndexStorage, imms *InMemoryStorage) func(sdk.Conte
index, exist := imms.GetCidIndex(cid)
if !exist { // new cid
index = cis.GetOrPutCidIndex(ctx, cid)
imms.AddCid(cid, index)
}
return index
}
Expand Down
91 changes: 91 additions & 0 deletions cosmos/poc/app/rank/calculate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package rank

import (
. "github.com/cybercongress/cyberd/cosmos/poc/app/storage"
"math"
)

const (
d = 0.85
tolerance = 0.1
)

func CalculateRank(data *InMemoryStorage) []float64 {

size := data.GetCidsCount()

if size == 0 {
return []float64{}
}
inverseOfSize := 1.0 / float64(size)

prevrank := data.GetRank()
zeros := make([]float64, size-len(prevrank))
prevrank = append(prevrank, zeros...)

tOverSize := (1.0 - d) / float64(size)
danglingNodes := calculateDanglingNodes(data)

for i := range danglingNodes {
prevrank[i] = inverseOfSize
}

change := 2.0

var rank []float64
for change > tolerance {
rank = step(tOverSize, prevrank, danglingNodes, data)
change = calculateChange(prevrank, rank)
prevrank = rank
}

return rank
}

func calculateDanglingNodes(data *InMemoryStorage) []int64 {

outLinks := data.GetOutLinks()
danglingNodes := make([]int64, 0, len(outLinks))

for i, cidLinks := range outLinks {
if len(cidLinks) == 0 {
danglingNodes = append(danglingNodes, int64(i))
}
}

return danglingNodes
}

func step(tOverSize float64, prevrank []float64, danglingNodes []int64, data *InMemoryStorage) []float64 {

innerProduct := 0.0
for _, danglingNode := range danglingNodes {
innerProduct += prevrank[danglingNode]
}

innerProductOverSize := innerProduct / float64(len(prevrank))
rank := make([]float64, len(prevrank))

for i, inLinksForI := range data.GetInLinks() {
ksum := 0.0

for j := range inLinksForI {
linkStake := float64(data.GetOverallLinkStake(CidNumber(j), CidNumber(i)))
jCidOutStake := float64(data.GetOverallOutLinksStake(CidNumber(j)))
ksum += prevrank[j] * (linkStake / jCidOutStake)
}

rank[i] = d*(ksum+innerProductOverSize) + tOverSize
}
return rank
}

func calculateChange(prevrank, rank []float64) float64 {

acc := 0.0
for i, pForI := range prevrank {
acc += math.Abs(pForI - rank[i])
}

return acc
}
30 changes: 7 additions & 23 deletions cosmos/poc/app/storage/cids.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,15 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

var lastCidNumber = []byte("cids_count")

type CidIndexStorage struct {
mainStoreKey *sdk.KVStoreKey
indexKey *sdk.KVStoreKey
ms MainStorage
indexKey *sdk.KVStoreKey
}

func NewCidIndexStorage(mainStoreKey *sdk.KVStoreKey, indexKey *sdk.KVStoreKey) CidIndexStorage {
func NewCidIndexStorage(ms MainStorage, indexKey *sdk.KVStoreKey) CidIndexStorage {
return CidIndexStorage{
mainStoreKey: mainStoreKey,
indexKey: indexKey,
ms: ms,
indexKey: indexKey,
}
}

Expand All @@ -32,32 +30,18 @@ func (cis CidIndexStorage) GetOrPutCidIndex(ctx sdk.Context, cid Cid) CidNumber
// new cid, get new index
if cidIndexAsBytes == nil {

lastIndex := cis.GetCidsCount(ctx)
lastIndex := cis.ms.GetCidsCount(ctx)
lastIndexAsBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(lastIndexAsBytes, lastIndex)

mainStore := ctx.KVStore(cis.mainStoreKey)
cidsIndex.Set(cidAsBytes, lastIndexAsBytes)
mainStore.Set(lastCidNumber, lastIndexAsBytes)
cis.ms.SetLastCidIndex(ctx, lastIndexAsBytes)
return CidNumber(lastIndex)
}

return CidNumber(binary.LittleEndian.Uint64(cidIndexAsBytes))
}

// returns overall added cids count
func (cis CidIndexStorage) GetCidsCount(ctx sdk.Context) uint64 {

mainStore := ctx.KVStore(cis.mainStoreKey)
lastIndexAsBytes := mainStore.Get(lastCidNumber)

if lastIndexAsBytes == nil {
return 0
}

return binary.LittleEndian.Uint64(lastIndexAsBytes) + 1
}

// returns all added cids
func (cis CidIndexStorage) GetFullCidsIndex(ctx sdk.Context) map[Cid]CidNumber {

Expand Down
52 changes: 51 additions & 1 deletion cosmos/poc/app/storage/inmemory.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type InMemoryStorage struct {

cidsCount uint64
cidsIndexes map[Cid]CidNumber
cidRank []float64
cidRank []float64 // array index is cid number

userStake map[AccountNumber]int64
}
Expand Down Expand Up @@ -54,3 +54,53 @@ func (s *InMemoryStorage) AddLink(link LinkedCids) {
CidsLinks(s.outLinks).Put(link.FromCid, link.ToCid, link.Creator)
CidsLinks(s.inLinks).Put(link.ToCid, link.FromCid, link.Creator)
}

func (s *InMemoryStorage) AddCid(cid Cid, number CidNumber) {
s.cidsIndexes[cid] = number
}

//
func (s *InMemoryStorage) GetOverallLinkStake(from CidNumber, to CidNumber) int64 {

stake := int64(0)
users := s.outLinks[from][to]
for user := range users {
stake += s.userStake[user]
}
return stake
}

func (s *InMemoryStorage) GetOverallOutLinksStake(from CidNumber) int64 {

stake := int64(0)
for to := range s.outLinks[from] {
stake += s.GetOverallLinkStake(from, to)
}
return stake
}

func (s *InMemoryStorage) UpdateRank(newCidRank []float64) {
s.cidRank = newCidRank
}

//
// GETTERS
func (s *InMemoryStorage) GetRank() []float64 {
return s.cidRank
}

func (s *InMemoryStorage) GetInLinks() map[CidNumber]CidLinks {
return s.inLinks
}

func (s *InMemoryStorage) GetOutLinks() map[CidNumber]CidLinks {
return s.outLinks
}

func (s *InMemoryStorage) GetStakes() map[AccountNumber]int64 {
return s.userStake
}

func (s *InMemoryStorage) GetCidsCount() int {
return len(s.cidsIndexes)
}
48 changes: 48 additions & 0 deletions cosmos/poc/app/storage/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package storage

import (
"encoding/binary"
sdk "github.com/cosmos/cosmos-sdk/types"
)

var lastCidNumber = []byte("cyberd_cids_count")
var lastAppHash = []byte("cyberd_app_hash")

type MainStorage struct {
key *sdk.KVStoreKey
}

func NewMainStorage(key *sdk.KVStoreKey) MainStorage {
return MainStorage{key: key}
}

// returns overall added cids count
func (ms MainStorage) GetCidsCount(ctx sdk.Context) uint64 {

mainStore := ctx.KVStore(ms.key)
lastIndexAsBytes := mainStore.Get(lastCidNumber)

if lastIndexAsBytes == nil {
return 0
}

return binary.LittleEndian.Uint64(lastIndexAsBytes) + 1
}

func (ms MainStorage) SetLastCidIndex(ctx sdk.Context, cidsCount []byte) {

mainStore := ctx.KVStore(ms.key)
mainStore.Set(lastCidNumber, cidsCount)
}

func (ms MainStorage) GetAppHash(ctx sdk.Context) []byte {

store := ctx.KVStore(ms.key)
return store.Get(lastAppHash)
}

func (ms MainStorage) StoreAppHash(ctx sdk.Context, hash []byte) {

store := ctx.KVStore(ms.key)
store.Set(lastAppHash, hash)
}
Loading

0 comments on commit 4267153

Please sign in to comment.