Skip to content

Commit

Permalink
Merge branch 'dev' into testnet
Browse files Browse the repository at this point in the history
# Conflicts:
#	upgrades/blocks.go
#	version/version.go
  • Loading branch information
danil-lashin committed Mar 10, 2020
2 parents b38ae98 + d2a6daa commit 7a2760f
Show file tree
Hide file tree
Showing 9 changed files with 262 additions and 16 deletions.
204 changes: 204 additions & 0 deletions core/state/candidates/candidates.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/MinterTeam/minter-go-node/helpers"
"github.com/MinterTeam/minter-go-node/rlp"
"github.com/MinterTeam/minter-go-node/tree"
"github.com/MinterTeam/minter-go-node/upgrades"
"math/big"
"sort"
"sync"
Expand Down Expand Up @@ -219,6 +220,16 @@ func (c *Candidates) GetCandidateByTendermintAddress(address types.TmAddress) *C
}

func (c *Candidates) RecalculateStakes(height uint64) {
if height >= upgrades.UpgradeBlock3 {
c.recalculateStakesNew(height)
} else if height >= upgrades.UpgradeBlock2 {
c.recalculateStakesOld2(height)
} else {
c.recalculateStakesOld1(height)
}
}

func (c *Candidates) recalculateStakesOld1(height uint64) {
coinsCache := newCoinsCache()

for _, pubkey := range c.getOrderedCandidates() {
Expand Down Expand Up @@ -313,6 +324,199 @@ func (c *Candidates) RecalculateStakes(height uint64) {
}
}

func (c *Candidates) recalculateStakesOld2(height uint64) {
coinsCache := newCoinsCache()

for _, pubkey := range c.getOrderedCandidates() {
candidate := c.getFromMap(pubkey)
stakes := c.GetStakes(candidate.PubKey)
for _, stake := range stakes {
stake.setBipValue(c.calculateBipValue(stake.Coin, stake.Value, false, true, coinsCache))
}

// apply updates for existing stakes
candidate.FilterUpdates()
for _, update := range candidate.updates {
stake := c.GetStakeOfAddress(candidate.PubKey, update.Owner, update.Coin)
if stake != nil {
stake.addValue(update.Value)
update.setValue(big.NewInt(0))
stake.setBipValue(c.calculateBipValue(stake.Coin, stake.Value, false, true, coinsCache))
}
}

candidate.FilterUpdates()
for _, update := range candidate.updates {
update.setBipValue(c.calculateBipValue(update.Coin, update.Value, false, true, coinsCache))
}

for _, update := range candidate.updates {
// find and replace smallest stake
index := -1
var smallestStake *big.Int

if len(stakes) == 0 {
index = 0
smallestStake = big.NewInt(0)
} else if len(stakes) < MaxDelegatorsPerCandidate {
for i, stake := range stakes {
if stake == nil {
index = i
break
}
}

if index == -1 {
index = len(stakes)
}

smallestStake = big.NewInt(0)
} else {
for i, stake := range stakes {
if stake == nil {
index = i
smallestStake = big.NewInt(0)
break
}

if smallestStake == nil || smallestStake.Cmp(stake.BipValue) == 1 {
smallestStake = big.NewInt(0).Set(stake.BipValue)
index = i
}
}
}

if index == -1 || smallestStake.Cmp(update.BipValue) == 1 {
c.bus.Events().AddEvent(uint32(height), eventsdb.UnbondEvent{
Address: update.Owner,
Amount: update.Value.String(),
Coin: update.Coin,
ValidatorPubKey: candidate.PubKey,
})
c.bus.Accounts().AddBalance(update.Owner, update.Coin, update.Value)
c.bus.Checker().AddCoin(update.Coin, big.NewInt(0).Neg(update.Value))
update.setValue(big.NewInt(0))
continue
}

if len(stakes) > index && stakes[index] != nil {
c.bus.Events().AddEvent(uint32(height), eventsdb.UnbondEvent{
Address: stakes[index].Owner,
Amount: stakes[index].Value.String(),
Coin: stakes[index].Coin,
ValidatorPubKey: candidate.PubKey,
})
c.bus.Accounts().AddBalance(stakes[index].Owner, stakes[index].Coin, stakes[index].Value)
c.bus.Checker().AddCoin(stakes[index].Coin, big.NewInt(0).Neg(stakes[index].Value))
}

candidate.SetStakeAtIndex(index, update, true)
stakes = c.GetStakes(candidate.PubKey)
}

candidate.clearUpdates()

totalBipValue := big.NewInt(0)
for _, stake := range c.GetStakes(candidate.PubKey) {
if stake == nil {
continue
}
totalBipValue.Add(totalBipValue, stake.BipValue)
}

candidate.setTotalBipStake(totalBipValue)
candidate.updateStakesCount()
}
}

func (c *Candidates) recalculateStakesNew(height uint64) {
coinsCache := newCoinsCache()

for _, pubkey := range c.getOrderedCandidates() {
candidate := c.getFromMap(pubkey)
stakes := &candidate.stakes
for _, stake := range stakes {
if stake == nil {
continue
}
stake.setBipValue(c.calculateBipValue(stake.Coin, stake.Value, false, true, coinsCache))
}

// apply updates for existing stakes
for _, update := range candidate.updates {
stake := c.GetStakeOfAddress(candidate.PubKey, update.Owner, update.Coin)
if stake != nil {
stake.addValue(update.Value)
update.setValue(big.NewInt(0))
stake.setBipValue(c.calculateBipValue(stake.Coin, stake.Value, false, true, coinsCache))
}
}

candidate.FilterUpdates()
for _, update := range candidate.updates {
update.setBipValue(c.calculateBipValue(update.Coin, update.Value, false, true, coinsCache))
}

for _, update := range candidate.updates {
// find and replace smallest stake
index := -1
var smallestStake *big.Int

for i, stake := range stakes {
if stake == nil {
index = i
smallestStake = big.NewInt(0)
break
}

if smallestStake == nil || smallestStake.Cmp(stake.BipValue) == 1 {
smallestStake = big.NewInt(0).Set(stake.BipValue)
index = i
}
}

if index == -1 || smallestStake.Cmp(update.BipValue) == 1 {
c.bus.Events().AddEvent(uint32(height), eventsdb.UnbondEvent{
Address: update.Owner,
Amount: update.Value.String(),
Coin: update.Coin,
ValidatorPubKey: candidate.PubKey,
})
c.bus.Accounts().AddBalance(update.Owner, update.Coin, update.Value)
c.bus.Checker().AddCoin(update.Coin, big.NewInt(0).Neg(update.Value))
update.setValue(big.NewInt(0))
continue
}

if len(stakes) > index && stakes[index] != nil {
c.bus.Events().AddEvent(uint32(height), eventsdb.UnbondEvent{
Address: stakes[index].Owner,
Amount: stakes[index].Value.String(),
Coin: stakes[index].Coin,
ValidatorPubKey: candidate.PubKey,
})
c.bus.Accounts().AddBalance(stakes[index].Owner, stakes[index].Coin, stakes[index].Value)
c.bus.Checker().AddCoin(stakes[index].Coin, big.NewInt(0).Neg(stakes[index].Value))
}

candidate.SetStakeAtIndex(index, update, true)
}

candidate.clearUpdates()

totalBipValue := big.NewInt(0)
for _, stake := range stakes {
if stake == nil {
continue
}
totalBipValue.Add(totalBipValue, stake.BipValue)
}

candidate.setTotalBipStake(totalBipValue)
candidate.updateStakesCount()
}
}

func (c *Candidates) Exists(pubkey types.Pubkey) bool {
c.lock.RLock()
defer c.lock.RUnlock()
Expand Down
32 changes: 32 additions & 0 deletions core/state/candidates/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/MinterTeam/minter-go-node/core/types"
"github.com/tendermint/tendermint/crypto/ed25519"
"math/big"
"sort"
)

type Candidate struct {
Expand Down Expand Up @@ -105,6 +106,37 @@ func (candidate *Candidate) GetFilteredUpdates() []*Stake {
return updates
}

func (candidate *Candidate) FilterUpdates() {
var updates []*Stake
for _, update := range candidate.updates {
// skip updates with 0 stakes
if update.Value.Cmp(big.NewInt(0)) != 1 {
continue
}

// merge updates
merged := false
for _, u := range updates {
if u.Coin == update.Coin && u.Owner == update.Owner {
u.Value.Add(u.Value, update.Value)
merged = true
break
}
}

if !merged {
updates = append(updates, update)
}
}

sort.SliceStable(updates, func(i, j int) bool {
return updates[i].BipValue.Cmp(updates[j].BipValue) == 1
})

candidate.updates = updates
candidate.isUpdatesDirty = true
}

func (candidate *Candidate) updateStakesCount() {
count := 0
for _, stake := range candidate.stakes {
Expand Down
23 changes: 13 additions & 10 deletions core/state/candidates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import (
eventsdb "github.com/MinterTeam/events-db"
"github.com/MinterTeam/minter-go-node/core/state/candidates"
"github.com/MinterTeam/minter-go-node/core/types"
"github.com/MinterTeam/minter-go-node/upgrades"
"github.com/tendermint/tendermint/crypto/ed25519"
db "github.com/tendermint/tm-db"
"math/big"
"testing"
)

const height = upgrades.UpgradeBlock2

func TestSimpleDelegate(t *testing.T) {
st := getState()

Expand All @@ -21,7 +24,7 @@ func TestSimpleDelegate(t *testing.T) {
pubkey := createTestCandidate(st)

st.Candidates.Delegate(address, pubkey, coin, amount, big.NewInt(0))
st.Candidates.RecalculateStakes(1)
st.Candidates.RecalculateStakes(height)

stake := st.Candidates.GetStakeOfAddress(pubkey, address, coin)
if stake == nil {
Expand Down Expand Up @@ -51,7 +54,7 @@ func TestDelegate(t *testing.T) {
totalAmount.Add(totalAmount, amount)
}

st.Candidates.RecalculateStakes(1)
st.Candidates.RecalculateStakes(height)

stake := st.Candidates.GetStakeOfAddress(pubkey, address, coin)
if stake == nil {
Expand Down Expand Up @@ -80,7 +83,7 @@ func TestComplexDelegate(t *testing.T) {
st.Candidates.Delegate(addr, pubkey, coin, amount, big.NewInt(0))
}

st.Candidates.RecalculateStakes(1)
st.Candidates.RecalculateStakes(height)

for i := uint64(0); i < 1000; i++ {
var addr types.Address
Expand Down Expand Up @@ -116,7 +119,7 @@ func TestComplexDelegate(t *testing.T) {
binary.BigEndian.PutUint64(addr[:], 3000)
st.Candidates.Delegate(addr, pubkey, coin, big.NewInt(3000), big.NewInt(0))

st.Candidates.RecalculateStakes(1)
st.Candidates.RecalculateStakes(height)

replacedAddress := types.HexToAddress("Mx00000000000003e7000000000000000000000000")
stake := st.Candidates.GetStakeOfAddress(pubkey, replacedAddress, coin)
Expand All @@ -139,7 +142,7 @@ func TestComplexDelegate(t *testing.T) {
binary.BigEndian.PutUint64(addr2[:], 3500)
st.Candidates.Delegate(addr2, pubkey, coin, big.NewInt(3500), big.NewInt(0))

st.Candidates.RecalculateStakes(1)
st.Candidates.RecalculateStakes(height)

stake := st.Candidates.GetStakeOfAddress(pubkey, addr, coin)
if stake == nil {
Expand All @@ -158,7 +161,7 @@ func TestComplexDelegate(t *testing.T) {
binary.BigEndian.PutUint64(addr[:], 4001)
st.Candidates.Delegate(addr, pubkey, coin, big.NewInt(900), big.NewInt(0))

st.Candidates.RecalculateStakes(1)
st.Candidates.RecalculateStakes(height)

stake := st.Candidates.GetStakeOfAddress(pubkey, addr, coin)
if stake != nil {
Expand All @@ -180,7 +183,7 @@ func TestStakeSufficiency(t *testing.T) {
st.Candidates.Delegate(addr, pubkey, coin, amount, big.NewInt(0))
}

st.Candidates.RecalculateStakes(1)
st.Candidates.RecalculateStakes(height)

{
stake := big.NewInt(1)
Expand Down Expand Up @@ -227,7 +230,7 @@ func TestDoubleSignPenalty(t *testing.T) {
binary.BigEndian.PutUint64(addr[:], 1)
st.Candidates.Delegate(addr, pubkey, coin, amount, big.NewInt(0))

st.Candidates.RecalculateStakes(1)
st.Candidates.RecalculateStakes(height)

var pk ed25519.PubKeyEd25519
copy(pk[:], pubkey[:])
Expand Down Expand Up @@ -274,7 +277,7 @@ func TestAbsentPenalty(t *testing.T) {
binary.BigEndian.PutUint64(addr[:], 1)
st.Candidates.Delegate(addr, pubkey, coin, amount, big.NewInt(0))

st.Candidates.RecalculateStakes(1)
st.Candidates.RecalculateStakes(height)

var pk ed25519.PubKeyEd25519
copy(pk[:], pubkey[:])
Expand Down Expand Up @@ -305,7 +308,7 @@ func TestDoubleAbsentPenalty(t *testing.T) {
st.Candidates.Delegate(addr, pubkey, coin, amount, big.NewInt(0))
st.Candidates.SetOnline(pubkey)

st.Candidates.RecalculateStakes(1)
st.Candidates.RecalculateStakes(height)

var pk ed25519.PubKeyEd25519
copy(pk[:], pubkey[:])
Expand Down
3 changes: 2 additions & 1 deletion core/transaction/declare_candidacy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/MinterTeam/minter-go-node/crypto"
"github.com/MinterTeam/minter-go-node/helpers"
"github.com/MinterTeam/minter-go-node/rlp"
"github.com/MinterTeam/minter-go-node/upgrades"
"math/big"
"sync"
"testing"
Expand Down Expand Up @@ -113,7 +114,7 @@ func TestDeclareCandidacyTxOverflow(t *testing.T) {
cState.Candidates.Delegate(types.Address{}, pubkey, types.GetBaseCoin(), helpers.BipToPip(big.NewInt(10)), helpers.BipToPip(big.NewInt(10)))
}

cState.Candidates.RecalculateStakes(0)
cState.Candidates.RecalculateStakes(upgrades.UpgradeBlock2)

privateKey, _ := crypto.GenerateKey()
addr := crypto.PubkeyToAddress(privateKey.PublicKey)
Expand Down
Loading

0 comments on commit 7a2760f

Please sign in to comment.