Skip to content

Commit

Permalink
Merge pull request #300 from MinterTeam/dev
Browse files Browse the repository at this point in the history
v1.1.2
  • Loading branch information
danil-lashin authored Mar 8, 2020
2 parents 6633efc + a0d6161 commit 7434425
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 16 deletions.
114 changes: 114 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,14 @@ func (c *Candidates) GetCandidateByTendermintAddress(address types.TmAddress) *C
}

func (c *Candidates) RecalculateStakes(height uint64) {
if height < upgrades.UpgradeBlock2 {
c.recalculateStakesOld(height)
} else {
c.recalculateStakesNew(height)
}
}

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

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

func (c *Candidates) recalculateStakesNew(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) 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
3 changes: 2 additions & 1 deletion core/transaction/delegate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,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"
"math/rand"
"sync"
Expand Down Expand Up @@ -80,7 +81,7 @@ func TestDelegateTx(t *testing.T) {
t.Fatalf("Target %s balance is not correct. Expected %s, got %s", coin, targetBalance, balance)
}

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

stake := cState.Candidates.GetStakeOfAddress(pubkey, addr, coin)

Expand Down
5 changes: 3 additions & 2 deletions core/transaction/unbond_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,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 All @@ -24,7 +25,7 @@ func TestUnbondTx(t *testing.T) {
value := helpers.BipToPip(big.NewInt(100))
cState.Candidates.Delegate(addr, pubkey, coin, value, big.NewInt(0))

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

data := UnbondData{
PubKey: pubkey,
Expand Down Expand Up @@ -64,7 +65,7 @@ func TestUnbondTx(t *testing.T) {
t.Fatalf("Response code is not 0. Error %s", response.Log)
}

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

targetBalance, _ := big.NewInt(0).SetString("999999800000000000000000", 10)
balance := cState.Accounts.GetBalance(addr, coin)
Expand Down
1 change: 1 addition & 0 deletions upgrades/blocks.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
package upgrades

const UpgradeBlock1 = 5000
const UpgradeBlock2 = 38519
1 change: 1 addition & 0 deletions upgrades/grace.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package upgrades
var gracePeriods = []*gracePeriod{
NewGracePeriod(1, 120),
NewGracePeriod(UpgradeBlock1, UpgradeBlock1+120),
NewGracePeriod(UpgradeBlock2, UpgradeBlock2+120),
}

type gracePeriod struct {
Expand Down
4 changes: 2 additions & 2 deletions version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ package version
const (
Maj = "1"
Min = "1"
Fix = "0"
Fix = "2"

AppVer = 6
)

var (
// Must be a string because scripts like dist.sh read this file.
Version = "1.1.1"
Version = "1.1.2"

// GitCommit is the current HEAD set using ldflags.
GitCommit string
Expand Down

0 comments on commit 7434425

Please sign in to comment.