diff --git a/cli/service/service.go b/cli/service/service.go index 259da154d..1cb5d7eb1 100644 --- a/cli/service/service.go +++ b/cli/service/service.go @@ -6,8 +6,8 @@ import ( pb "github.com/MinterTeam/minter-go-node/cli/cli_pb" "github.com/MinterTeam/minter-go-node/config" "github.com/MinterTeam/minter-go-node/core/minter" + "github.com/MinterTeam/minter-go-node/core/state/candidates" "github.com/MinterTeam/minter-go-node/core/types" - "github.com/MinterTeam/minter-go-node/legacy/candidates" "github.com/MinterTeam/minter-go-node/version" "github.com/golang/protobuf/ptypes" "github.com/golang/protobuf/ptypes/empty" diff --git a/cmd/minter/cmd/export.go b/cmd/minter/cmd/export.go index fb86f18c2..2befc9d20 100644 --- a/cmd/minter/cmd/export.go +++ b/cmd/minter/cmd/export.go @@ -73,7 +73,7 @@ func export(cmd *cobra.Command, args []string) error { log.Panicf("Cannot new state at given height: %s", err) } - exportTimeStart, newState := time.Now(), currentState.Export11To12(height) + exportTimeStart, newState := time.Now(), currentState.Export(height) fmt.Printf("State has been exported. Took %s", time.Since(exportTimeStart)) if startHeight > 0 { diff --git a/core/state/state.go b/core/state/state.go index 07c5f5bd6..0a863ed57 100644 --- a/core/state/state.go +++ b/core/state/state.go @@ -17,11 +17,6 @@ import ( "github.com/MinterTeam/minter-go-node/core/state/waitlist" "github.com/MinterTeam/minter-go-node/core/types" "github.com/MinterTeam/minter-go-node/helpers" - legacyAccounts "github.com/MinterTeam/minter-go-node/legacy/accounts" - legacyApp "github.com/MinterTeam/minter-go-node/legacy/app" - legacyCandidates "github.com/MinterTeam/minter-go-node/legacy/candidates" - legacyCoins "github.com/MinterTeam/minter-go-node/legacy/coins" - legacyFrozenfunds "github.com/MinterTeam/minter-go-node/legacy/frozenfunds" "github.com/MinterTeam/minter-go-node/tree" db "github.com/tendermint/tm-db" "gopkg.in/errgo.v2/fmt/errors" @@ -95,57 +90,6 @@ func (cs *CheckState) Tree() tree.ReadOnlyTree { return cs.state.Tree() } -func (cs *CheckState) Export11To12(height uint64) types.AppState { - iavlTree := cs.state.tree - - candidatesState, err := legacyCandidates.NewCandidates(nil, iavlTree) - if err != nil { - log.Panicf("Create new state at height %d failed: %s", height, err) - } - - validatorsState, err := validators.NewValidators(nil, iavlTree) - if err != nil { - log.Panicf("Create new state at height %d failed: %s", height, err) - } - - appState, err := legacyApp.NewApp(nil, iavlTree) - if err != nil { - log.Panicf("Create new state at height %d failed: %s", height, err) - } - - frozenFundsState, err := legacyFrozenfunds.NewFrozenFunds(nil, iavlTree) - if err != nil { - log.Panicf("Create new state at height %d failed: %s", height, err) - } - - accountsState, err := legacyAccounts.NewAccounts(nil, iavlTree) - if err != nil { - log.Panicf("Create new state at height %d failed: %s", height, err) - } - - coinsState, err := legacyCoins.NewCoins(nil, iavlTree) - if err != nil { - log.Panicf("Create new state at height %d failed: %s", height, err) - } - - checksState, err := checks.NewChecks(iavlTree) - if err != nil { - log.Panicf("Create new state at height %d failed: %s", height, err) - } - - state := new(types.AppState) - appState.Export(state, height) - coinsMap := coinsState.Export(state) - validatorsState.Export(state) - candidatesMap := candidatesState.Export(state, coinsMap) - frozenFundsState.Export(state, height, coinsMap, candidatesMap) - accountsState.Export(state, coinsMap) - checksState.Export(state) - coinsState.Export(state) - - return *state -} - type State struct { App *app.App Validators *validators.Validators diff --git a/legacy/accounts/accounts.go b/legacy/accounts/accounts.go deleted file mode 100644 index b330833ad..000000000 --- a/legacy/accounts/accounts.go +++ /dev/null @@ -1,210 +0,0 @@ -package accounts - -import ( - "fmt" - "github.com/MinterTeam/minter-go-node/core/state/bus" - "github.com/MinterTeam/minter-go-node/core/types" - "github.com/MinterTeam/minter-go-node/rlp" - "github.com/MinterTeam/minter-go-node/tree" - "math/big" - "sort" - "sync" -) - -const mainPrefix = byte('a') -const coinsPrefix = byte('c') -const balancePrefix = byte('b') - -type Accounts struct { - list map[types.Address]*Model - dirty map[types.Address]struct{} - - iavl tree.MTree - bus *bus.Bus - - lock sync.RWMutex -} - -func NewAccounts(stateBus *bus.Bus, iavl tree.MTree) (*Accounts, error) { - accounts := &Accounts{iavl: iavl, bus: stateBus, list: map[types.Address]*Model{}, dirty: map[types.Address]struct{}{}} - return accounts, nil -} - -func (a *Accounts) GetBalance(address types.Address, coin types.CoinSymbol) *big.Int { - account := a.getOrNew(address) - if !account.hasCoin(coin) { - return big.NewInt(0) - } - - if _, ok := account.balances[coin]; !ok { - balance := big.NewInt(0) - - path := []byte{mainPrefix} - path = append(path, address[:]...) - path = append(path, balancePrefix) - path = append(path, coin[:]...) - - _, enc := a.iavl.Get(path) - if len(enc) != 0 { - balance = big.NewInt(0).SetBytes(enc) - } - - account.balances[coin] = balance - } - - return big.NewInt(0).Set(account.balances[coin]) -} - -func (a *Accounts) get(address types.Address) *Model { - if account := a.getFromMap(address); account != nil { - return account - } - - path := []byte{mainPrefix} - path = append(path, address[:]...) - _, enc := a.iavl.Get(path) - if len(enc) == 0 { - return nil - } - - account := &Model{} - if err := rlp.DecodeBytes(enc, account); err != nil { - panic(fmt.Sprintf("failed to decode account at address %s: %s", address.String(), err)) - } - - account.address = address - account.balances = map[types.CoinSymbol]*big.Int{} - account.markDirty = a.markDirty - account.dirtyBalances = map[types.CoinSymbol]struct{}{} - - // load coins - path = []byte{mainPrefix} - path = append(path, address[:]...) - path = append(path, coinsPrefix) - _, enc = a.iavl.Get(path) - if len(enc) != 0 { - var coins []types.CoinSymbol - if err := rlp.DecodeBytes(enc, &coins); err != nil { - panic(fmt.Sprintf("failed to decode coins list at address %s: %s", address.String(), err)) - } - - account.coins = coins - } - - a.setToMap(address, account) - return account -} - -func (a *Accounts) getOrNew(address types.Address) *Model { - account := a.get(address) - if account == nil { - account = &Model{ - Nonce: 0, - address: address, - coins: []types.CoinSymbol{}, - balances: map[types.CoinSymbol]*big.Int{}, - markDirty: a.markDirty, - dirtyBalances: map[types.CoinSymbol]struct{}{}, - isNew: true, - } - a.setToMap(address, account) - } - - return account -} - -func (a *Accounts) GetNonce(address types.Address) uint64 { - account := a.getOrNew(address) - - return account.Nonce -} - -func (a *Accounts) GetBalances(address types.Address) map[types.CoinSymbol]*big.Int { - account := a.getOrNew(address) - - balances := make(map[types.CoinSymbol]*big.Int, len(account.coins)) - for _, coin := range account.coins { - balances[coin] = a.GetBalance(address, coin) - } - - return balances -} - -func (a *Accounts) markDirty(addr types.Address) { - a.dirty[addr] = struct{}{} -} - -func (a *Accounts) Export(state *types.AppState, coinsMap map[types.CoinSymbol]types.Coin) { - // todo: iterate range? - a.iavl.Iterate(func(key []byte, value []byte) bool { - if key[0] == mainPrefix { - addressPath := key[1:] - if len(addressPath) > types.AddressLength { - return false - } - - address := types.BytesToAddress(addressPath) - account := a.get(address) - - var balance []types.Balance - for coinSymbol, value := range a.GetBalances(account.address) { - coin := coinsMap[coinSymbol] - - // set account address as owner address of coin if account contains whole volume - if coin.Reserve == value.String() { - state.Coins[coin.ID-1].OwnerAddress = &account.address - } - - balance = append(balance, types.Balance{ - Coin: coin.ID, - Value: value.String(), - }) - } - - // sort balances by coin symbol - sort.SliceStable(balance, func(i, j int) bool { - return balance[i].Coin > balance[j].Coin - }) - - acc := types.Account{ - Address: account.address, - Balance: balance, - Nonce: account.Nonce, - } - - if account.IsMultisig() { - var weights []uint64 - for _, weight := range account.MultisigData.Weights { - weights = append(weights, uint64(weight)) - } - acc.MultisigData = &types.Multisig{ - Weights: weights, - Threshold: uint64(account.MultisigData.Threshold), - Addresses: account.MultisigData.Addresses, - } - } - - state.Accounts = append(state.Accounts, acc) - } - - return false - }) -} - -func (a *Accounts) GetAccount(address types.Address) *Model { - return a.getOrNew(address) -} - -func (a *Accounts) getFromMap(address types.Address) *Model { - a.lock.RLock() - defer a.lock.RUnlock() - - return a.list[address] -} - -func (a *Accounts) setToMap(address types.Address, model *Model) { - a.lock.Lock() - defer a.lock.Unlock() - - a.list[address] = model -} diff --git a/legacy/accounts/model.go b/legacy/accounts/model.go deleted file mode 100644 index ef67c6fb4..000000000 --- a/legacy/accounts/model.go +++ /dev/null @@ -1,138 +0,0 @@ -package accounts - -import ( - "bytes" - "github.com/MinterTeam/minter-go-node/core/types" - "github.com/MinterTeam/minter-go-node/crypto" - "github.com/MinterTeam/minter-go-node/rlp" - "math/big" - "sort" -) - -type Model struct { - Nonce uint64 - MultisigData Multisig - - address types.Address - coins []types.CoinSymbol - balances map[types.CoinSymbol]*big.Int - - hasDirtyCoins bool - dirtyBalances map[types.CoinSymbol]struct{} - isDirty bool // nonce or multisig data - - isNew bool - - markDirty func(types.Address) -} - -type Multisig struct { - Threshold uint32 - Weights []uint32 - Addresses []types.Address -} - -func (m *Multisig) Address() types.Address { - b, err := rlp.EncodeToBytes(m) - if err != nil { - panic(err) - } - - var addr types.Address - copy(addr[:], crypto.Keccak256(b)[12:]) - - return addr -} - -func (m *Multisig) GetWeight(address types.Address) uint32 { - for i, addr := range m.Addresses { - if addr == address { - return m.Weights[i] - } - } - - return 0 -} - -func (model *Model) setNonce(nonce uint64) { - model.Nonce = nonce - model.isDirty = true - model.markDirty(model.address) -} - -func (model *Model) getBalance(coin types.CoinSymbol) *big.Int { - return model.balances[coin] -} - -func (model *Model) hasDirtyBalances() bool { - return len(model.dirtyBalances) > 0 -} - -func (model *Model) isBalanceDirty(coin types.CoinSymbol) bool { - _, exists := model.dirtyBalances[coin] - return exists -} - -func (model *Model) getOrderedCoins() []types.CoinSymbol { - keys := make([]types.CoinSymbol, 0, len(model.balances)) - for k := range model.balances { - keys = append(keys, k) - } - - sort.SliceStable(keys, func(i, j int) bool { - return bytes.Compare(keys[i].Bytes(), keys[j].Bytes()) == 1 - }) - - return keys -} - -func (model *Model) setBalance(coin types.CoinSymbol, amount *big.Int) { - if amount.Cmp(big.NewInt(0)) == 0 { - if !model.hasCoin(coin) { - return - } - - var newCoins []types.CoinSymbol - for _, c := range model.coins { - if coin == c { - continue - } - - newCoins = append(newCoins, c) - } - - model.hasDirtyCoins = true - model.coins = newCoins - model.balances[coin] = amount - model.dirtyBalances[coin] = struct{}{} - model.markDirty(model.address) - - return - } - - if !model.hasCoin(coin) { - model.hasDirtyCoins = true - model.coins = append(model.coins, coin) - } - model.dirtyBalances[coin] = struct{}{} - model.markDirty(model.address) - model.balances[coin] = amount -} - -func (model *Model) hasCoin(coin types.CoinSymbol) bool { - for _, c := range model.coins { - if c == coin { - return true - } - } - - return false -} - -func (model *Model) IsMultisig() bool { - return len(model.MultisigData.Weights) > 0 -} - -func (model *Model) Multisig() Multisig { - return model.MultisigData -} diff --git a/legacy/app/app.go b/legacy/app/app.go deleted file mode 100644 index ac38ca66d..000000000 --- a/legacy/app/app.go +++ /dev/null @@ -1,106 +0,0 @@ -package app - -import ( - "fmt" - "github.com/MinterTeam/minter-go-node/core/state/bus" - "github.com/MinterTeam/minter-go-node/core/types" - "github.com/MinterTeam/minter-go-node/rlp" - "github.com/MinterTeam/minter-go-node/tree" - "math/big" -) - -const mainPrefix = 'd' - -func (v *App) Tree() tree.ReadOnlyTree { - return v.iavl -} - -type App struct { - model *Model - isDirty bool - - bus *bus.Bus - iavl tree.MTree -} - -func NewApp(stateBus *bus.Bus, iavl tree.MTree) (*App, error) { - app := &App{bus: stateBus, iavl: iavl} - - return app, nil -} - -func (v *App) GetMaxGas() uint64 { - model := v.getOrNew() - - return model.getMaxGas() -} - -func (v *App) SetMaxGas(gas uint64) { - model := v.getOrNew() - model.setMaxGas(gas) -} - -func (v *App) GetTotalSlashed() *big.Int { - model := v.getOrNew() - - return model.getTotalSlashed() -} - -func (v *App) AddTotalSlashed(amount *big.Int) { - if amount.Cmp(big.NewInt(0)) == 0 { - return - } - - model := v.getOrNew() - model.setTotalSlashed(big.NewInt(0).Add(model.getTotalSlashed(), amount)) - v.bus.Checker().AddCoin(types.GetBaseCoinID(), amount) -} - -func (v *App) get() *Model { - if v.model != nil { - return v.model - } - - path := []byte{mainPrefix} - _, enc := v.iavl.Get(path) - if len(enc) == 0 { - return nil - } - - model := &Model{} - if err := rlp.DecodeBytes(enc, model); err != nil { - panic(fmt.Sprintf("failed to decode app model at: %s", err)) - } - - v.model = model - v.model.markDirty = v.markDirty - return v.model -} - -func (v *App) getOrNew() *Model { - model := v.get() - if model == nil { - model = &Model{ - TotalSlashed: big.NewInt(0), - MaxGas: 0, - markDirty: v.markDirty, - } - v.model = model - } - - return model -} - -func (v *App) markDirty() { - v.isDirty = true -} - -func (v *App) SetTotalSlashed(amount *big.Int) { - v.getOrNew().setTotalSlashed(amount) -} - -func (v *App) Export(state *types.AppState, height uint64) { - state.MaxGas = v.GetMaxGas() - state.TotalSlashed = v.GetTotalSlashed().String() - state.StartHeight = height -} diff --git a/legacy/app/model.go b/legacy/app/model.go deleted file mode 100644 index d502226f7..000000000 --- a/legacy/app/model.go +++ /dev/null @@ -1,36 +0,0 @@ -package app - -import "math/big" - -type Model struct { - TotalSlashed *big.Int - MaxGas uint64 - - markDirty func() -} - -func (model *Model) getMaxGas() uint64 { - return model.MaxGas -} - -func (model *Model) setMaxGas(maxGas uint64) { - if model.MaxGas != maxGas { - model.markDirty() - } - model.MaxGas = maxGas -} - -func (model *Model) getTotalSlashed() *big.Int { - if model.TotalSlashed == nil { - return big.NewInt(0) - } - - return model.TotalSlashed -} - -func (model *Model) setTotalSlashed(totalSlashed *big.Int) { - if model.TotalSlashed.Cmp(totalSlashed) != 0 { - model.markDirty() - } - model.TotalSlashed = totalSlashed -} diff --git a/legacy/candidates/candidates.go b/legacy/candidates/candidates.go deleted file mode 100644 index 5d9d05e8c..000000000 --- a/legacy/candidates/candidates.go +++ /dev/null @@ -1,381 +0,0 @@ -package candidates - -import ( - "bytes" - "fmt" - "github.com/MinterTeam/minter-go-node/core/state/bus" - "github.com/MinterTeam/minter-go-node/core/types" - "github.com/MinterTeam/minter-go-node/rlp" - "github.com/MinterTeam/minter-go-node/tree" - "math/big" - "sort" - "sync" -) - -const ( - CandidateStatusOffline = 0x01 - CandidateStatusOnline = 0x02 - - UnbondPeriod = 518400 - MaxDelegatorsPerCandidate = 1000 - - mainPrefix = 'c' - stakesPrefix = 's' - totalStakePrefix = 't' - updatesPrefix = 'u' -) - -type Candidates struct { - list map[types.Pubkey]*Candidate - - iavl tree.MTree - bus *bus.Bus - - lock sync.RWMutex - loaded bool -} - -func NewCandidates(bus *bus.Bus, iavl tree.MTree) (*Candidates, error) { - candidates := &Candidates{iavl: iavl, bus: bus} - - return candidates, nil -} - -func (c *Candidates) GetNewCandidates(valCount int) []Candidate { - var result []Candidate - - candidates := c.GetCandidates() - for _, candidate := range candidates { - if candidate.Status == CandidateStatusOffline { - continue - } - - if candidate.totalBipStake.Cmp(big.NewInt(0)) == 0 { - continue - } - - result = append(result, *candidate) - } - - sort.Slice(result, func(i, j int) bool { - return result[i].totalBipStake.Cmp(result[j].totalBipStake) == 1 - }) - - if len(result) > valCount { - result = result[:valCount] - } - - return result -} - -func (c *Candidates) Create(ownerAddress types.Address, rewardAddress types.Address, pubkey types.Pubkey, commission uint32) { - candidate := &Candidate{ - PubKey: pubkey, - RewardAddress: rewardAddress, - OwnerAddress: ownerAddress, - Commission: commission, - Status: CandidateStatusOffline, - totalBipStake: big.NewInt(0), - stakes: [MaxDelegatorsPerCandidate]*Stake{}, - isDirty: true, - isTotalStakeDirty: true, - } - - candidate.setTmAddress() - c.setToMap(pubkey, candidate) -} - -func (c *Candidates) GetCandidateByTendermintAddress(address types.TmAddress) *Candidate { - candidates := c.GetCandidates() - for _, candidate := range candidates { - if candidate.GetTmAddress() == address { - return candidate - } - } - - return nil -} - -func (c *Candidates) Exists(pubkey types.Pubkey) bool { - c.lock.RLock() - defer c.lock.RUnlock() - - _, exists := c.list[pubkey] - - return exists -} - -func (c *Candidates) Count() int { - c.lock.RLock() - defer c.lock.RUnlock() - - return len(c.list) -} - -func (c *Candidates) GetCandidate(pubkey types.Pubkey) *Candidate { - return c.getFromMap(pubkey) -} - -func (c *Candidates) GetCandidates() []*Candidate { - var candidates []*Candidate - for _, pubkey := range c.getOrderedCandidates() { - candidates = append(candidates, c.getFromMap(pubkey)) - } - - return candidates -} - -func (c *Candidates) GetTotalStake(pubkey types.Pubkey) *big.Int { - candidate := c.getFromMap(pubkey) - if candidate.totalBipStake == nil { - path := []byte{mainPrefix} - path = append(path, pubkey[:]...) - path = append(path, totalStakePrefix) - _, enc := c.iavl.Get(path) - if len(enc) == 0 { - candidate.totalBipStake = big.NewInt(0) - return big.NewInt(0) - } - - candidate.totalBipStake = big.NewInt(0).SetBytes(enc) - } - - return candidate.totalBipStake -} - -func (c *Candidates) GetStakes(pubkey types.Pubkey) []*Stake { - candidate := c.GetCandidate(pubkey) - - var stakes []*Stake - for i := 0; i < MaxDelegatorsPerCandidate; i++ { - stake := candidate.stakes[i] - if stake == nil { - continue - } - stakes = append(stakes, stake) - } - - return stakes -} - -func (c *Candidates) StakesCount(pubkey types.Pubkey) int { - return c.GetCandidate(pubkey).stakesCount -} - -func (c *Candidates) GetStakeOfAddress(pubkey types.Pubkey, address types.Address, coin types.CoinSymbol) *Stake { - candidate := c.GetCandidate(pubkey) - for _, stake := range candidate.stakes { - if stake == nil { - continue - } - - if stake.Owner == address && stake.Coin == coin { - return stake - } - } - - return nil -} - -func (c *Candidates) GetStakeValueOfAddress(pubkey types.Pubkey, address types.Address, coin types.CoinSymbol) *big.Int { - stake := c.GetStakeOfAddress(pubkey, address, coin) - if stake == nil { - return nil - } - - return stake.Value -} - -func (c *Candidates) GetCandidateOwner(pubkey types.Pubkey) types.Address { - return c.getFromMap(pubkey).OwnerAddress -} - -func (c *Candidates) LoadCandidates() { - if c.loaded { - return - } - c.loaded = true - - path := []byte{mainPrefix} - _, enc := c.iavl.Get(path) - if len(enc) == 0 { - c.list = map[types.Pubkey]*Candidate{} - return - } - - var candidates []*Candidate - if err := rlp.DecodeBytes(enc, &candidates); err != nil { - panic(fmt.Sprintf("failed to decode candidates: %s", err)) - } - - c.list = map[types.Pubkey]*Candidate{} - for _, candidate := range candidates { - // load total stake - path = append([]byte{mainPrefix}, candidate.PubKey.Bytes()...) - path = append(path, totalStakePrefix) - _, enc = c.iavl.Get(path) - if len(enc) == 0 { - candidate.totalBipStake = big.NewInt(0) - } else { - candidate.totalBipStake = big.NewInt(0).SetBytes(enc) - } - - candidate.setTmAddress() - c.setToMap(candidate.PubKey, candidate) - } -} - -func (c *Candidates) LoadStakes() { - for pubkey := range c.list { - c.LoadStakesOfCandidate(pubkey) - } -} - -func (c *Candidates) Export(state *types.AppState, coinsMap map[types.CoinSymbol]types.Coin) map[types.Pubkey]uint32 { - c.LoadCandidates() - c.LoadStakes() - - candidatesMap := make(map[types.Pubkey]uint32) - - candidates, maxID := c.GetCandidates(), uint32(1) - for _, candidate := range candidates { - candidateStakes := c.GetStakes(candidate.PubKey) - stakes := make([]types.Stake, len(candidateStakes)) - for i, s := range candidateStakes { - stakes[i] = types.Stake{ - Owner: s.Owner, - Coin: coinsMap[s.Coin].ID, - Value: s.Value.String(), - BipValue: s.BipValue.String(), - } - } - - updates := make([]types.Stake, len(candidate.updates)) - for i, u := range candidate.updates { - updates[i] = types.Stake{ - Owner: u.Owner, - Coin: coinsMap[u.Coin].ID, - Value: u.Value.String(), - BipValue: u.BipValue.String(), - } - } - - state.Candidates = append(state.Candidates, types.Candidate{ - ID: uint64(maxID), - RewardAddress: candidate.RewardAddress, - OwnerAddress: candidate.OwnerAddress, - ControlAddress: candidate.OwnerAddress, - TotalBipStake: candidate.GetTotalBipStake().String(), - PubKey: candidate.PubKey, - Commission: uint64(candidate.Commission), - Status: uint64(candidate.Status), - Updates: updates, - Stakes: stakes, - }) - candidatesMap[candidate.PubKey] = maxID - - maxID++ - } - - return candidatesMap -} - -func (c *Candidates) getOrderedCandidates() []types.Pubkey { - c.lock.RLock() - defer c.lock.RUnlock() - - var keys []types.Pubkey - for _, candidate := range c.list { - keys = append(keys, candidate.PubKey) - } - - sort.SliceStable(keys, func(i, j int) bool { - return bytes.Compare(keys[i].Bytes(), keys[j].Bytes()) == 1 - }) - - return keys -} - -func (c *Candidates) getFromMap(pubkey types.Pubkey) *Candidate { - c.lock.RLock() - defer c.lock.RUnlock() - - return c.list[pubkey] -} - -func (c *Candidates) setToMap(pubkey types.Pubkey, model *Candidate) { - c.lock.Lock() - defer c.lock.Unlock() - - c.list[pubkey] = model -} - -func (c *Candidates) SetTotalStake(pubkey types.Pubkey, stake *big.Int) { - c.GetCandidate(pubkey).setTotalBipStake(stake) -} - -func (c *Candidates) LoadStakesOfCandidate(pubkey types.Pubkey) { - candidate := c.GetCandidate(pubkey) - - // load stakes - stakesCount := 0 - for index := 0; index < MaxDelegatorsPerCandidate; index++ { - path := []byte{mainPrefix} - path = append(path, candidate.PubKey.Bytes()...) - path = append(path, stakesPrefix) - path = append(path, []byte(fmt.Sprintf("%d", index))...) - _, enc := c.iavl.Get(path) - if len(enc) == 0 { - candidate.stakes[index] = nil - continue - } - - stake := &Stake{} - if err := rlp.DecodeBytes(enc, stake); err != nil { - panic(fmt.Sprintf("failed to decode stake: %s", err)) - } - - candidate.SetStakeAtIndex(index, stake, false) - - stakesCount++ - } - - candidate.stakesCount = stakesCount - - // load updates - path := []byte{mainPrefix} - path = append(path, candidate.PubKey.Bytes()...) - path = append(path, updatesPrefix) - _, enc := c.iavl.Get(path) - if len(enc) == 0 { - candidate.updates = nil - } else { - var updates []*Stake - if err := rlp.DecodeBytes(enc, &updates); err != nil { - panic(fmt.Sprintf("failed to decode updated: %s", err)) - } - - for _, update := range updates { - update.markDirty = (func(candidate *Candidate) func(int) { - return func(i int) { - candidate.isUpdatesDirty = true - } - })(candidate) - } - - candidate.updates = updates - } - - // load total stake - path = append([]byte{mainPrefix}, candidate.PubKey.Bytes()...) - path = append(path, totalStakePrefix) - _, enc = c.iavl.Get(path) - if len(enc) == 0 { - candidate.totalBipStake = big.NewInt(0) - } else { - candidate.totalBipStake = big.NewInt(0).SetBytes(enc) - } - - candidate.setTmAddress() - c.setToMap(candidate.PubKey, candidate) -} diff --git a/legacy/candidates/model.go b/legacy/candidates/model.go deleted file mode 100644 index 10c4395bf..000000000 --- a/legacy/candidates/model.go +++ /dev/null @@ -1,251 +0,0 @@ -package candidates - -import ( - "github.com/MinterTeam/minter-go-node/core/types" - "github.com/tendermint/tendermint/crypto/ed25519" - "math/big" - "sort" -) - -type Candidate struct { - PubKey types.Pubkey - RewardAddress types.Address - OwnerAddress types.Address - Commission uint32 - Status byte - - totalBipStake *big.Int - stakesCount int - stakes [MaxDelegatorsPerCandidate]*Stake - updates []*Stake - tmAddress *types.TmAddress - - isDirty bool - isTotalStakeDirty bool - isUpdatesDirty bool - dirtyStakes [MaxDelegatorsPerCandidate]bool -} - -func (candidate *Candidate) setStatus(status byte) { - candidate.isDirty = true - candidate.Status = status -} - -func (candidate *Candidate) setOwner(address types.Address) { - candidate.isDirty = true - candidate.OwnerAddress = address -} - -func (candidate *Candidate) setReward(address types.Address) { - candidate.isDirty = true - candidate.RewardAddress = address -} - -func (candidate *Candidate) addUpdate(stake *Stake) { - candidate.isUpdatesDirty = true - stake.markDirty = func(i int) { - candidate.isUpdatesDirty = true - } - candidate.updates = append(candidate.updates, stake) -} - -func (candidate *Candidate) clearUpdates() { - if len(candidate.updates) != 0 { - candidate.isUpdatesDirty = true - } - - candidate.updates = nil -} - -func (candidate *Candidate) setTotalBipStake(totalBipValue *big.Int) { - if totalBipValue.Cmp(candidate.totalBipStake) != 0 { - candidate.isTotalStakeDirty = true - } - - candidate.totalBipStake.Set(totalBipValue) -} - -func (candidate *Candidate) GetTmAddress() types.TmAddress { - return *candidate.tmAddress -} - -func (candidate *Candidate) setTmAddress() { - // set tm address - var pubkey ed25519.PubKeyEd25519 - copy(pubkey[:], candidate.PubKey[:]) - - var address types.TmAddress - copy(address[:], pubkey.Address().Bytes()) - - candidate.tmAddress = &address -} - -func (candidate *Candidate) GetFilteredUpdates() []*Stake { - 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) - } - } - - 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 { - if stake != nil { - count++ - } - } - candidate.stakesCount = count -} - -func (candidate *Candidate) GetTotalBipStake() *big.Int { - return big.NewInt(0).Set(candidate.totalBipStake) -} - -func (candidate *Candidate) SetStakeAtIndex(index int, stake *Stake, isDirty bool) { - stake.markDirty = func(i int) { - candidate.dirtyStakes[i] = true - } - stake.index = index - - candidate.stakes[index] = stake - - if isDirty { - stake.markDirty(index) - } -} - -type Stake struct { - Owner types.Address - Coin types.CoinSymbol - Value *big.Int - BipValue *big.Int - - index int - markDirty func(int) -} - -func (stake *Stake) addValue(value *big.Int) { - stake.markDirty(stake.index) - stake.Value.Add(stake.Value, value) -} - -func (stake *Stake) subValue(value *big.Int) { - stake.markDirty(stake.index) - stake.Value.Sub(stake.Value, value) -} - -func (stake *Stake) setBipValue(value *big.Int) { - if stake.BipValue.Cmp(value) != 0 { - stake.markDirty(stake.index) - } - - stake.BipValue.Set(value) -} - -func (stake *Stake) setNewOwner(coin types.CoinSymbol, owner types.Address) { - stake.Coin = coin - stake.Owner = owner - stake.BipValue = big.NewInt(0) - stake.Value = big.NewInt(0) - stake.markDirty(stake.index) -} - -func (stake *Stake) setValue(ret *big.Int) { - stake.markDirty(stake.index) - stake.Value.Set(ret) -} - -func (stake *Stake) setCoin(coin types.CoinSymbol) { - stake.markDirty(stake.index) - stake.Coin = coin -} - -type coinsCache struct { - list map[types.CoinSymbol]*coinsCacheItem -} - -func newCoinsCache() *coinsCache { - return &coinsCache{list: map[types.CoinSymbol]*coinsCacheItem{}} -} - -type coinsCacheItem struct { - totalPower *big.Int - totalAmount *big.Int -} - -func (c *coinsCache) Exists(symbol types.CoinSymbol) bool { - if c == nil { - return false - } - - _, exists := c.list[symbol] - - return exists -} - -func (c *coinsCache) Get(symbol types.CoinSymbol) (totalPower *big.Int, totalAmount *big.Int) { - return c.list[symbol].totalPower, c.list[symbol].totalAmount -} - -func (c *coinsCache) Set(symbol types.CoinSymbol, totalPower *big.Int, totalAmount *big.Int) { - if c == nil { - return - } - - if c.list[symbol] == nil { - c.list[symbol] = &coinsCacheItem{} - } - - c.list[symbol].totalAmount = totalAmount - c.list[symbol].totalPower = totalPower -} diff --git a/legacy/coins/coins.go b/legacy/coins/coins.go deleted file mode 100644 index 08638f44b..000000000 --- a/legacy/coins/coins.go +++ /dev/null @@ -1,200 +0,0 @@ -package coins - -import ( - "bytes" - "fmt" - "github.com/MinterTeam/minter-go-node/core/state/bus" - "github.com/MinterTeam/minter-go-node/core/types" - "github.com/MinterTeam/minter-go-node/helpers" - "github.com/MinterTeam/minter-go-node/rlp" - "github.com/MinterTeam/minter-go-node/tree" - "math/big" - "sort" - "sync" -) - -const ( - mainPrefix = byte('q') - infoPrefix = byte('i') -) - -type Coins struct { - list map[types.CoinSymbol]*Model - dirty map[types.CoinSymbol]struct{} - - bus *bus.Bus - iavl tree.MTree - - lock sync.RWMutex -} - -func NewCoins(stateBus *bus.Bus, iavl tree.MTree) (*Coins, error) { - coins := &Coins{bus: stateBus, iavl: iavl, list: map[types.CoinSymbol]*Model{}, dirty: map[types.CoinSymbol]struct{}{}} - - return coins, nil -} - -func (c *Coins) GetCoin(symbol types.CoinSymbol) *Model { - return c.get(symbol) -} - -func (c *Coins) Exists(symbol types.CoinSymbol) bool { - if symbol.IsBaseCoin() { - return true - } - - return c.get(symbol) != nil -} - -func (c *Coins) get(symbol types.CoinSymbol) *Model { - if coin := c.getFromMap(symbol); coin != nil { - return coin - } - - path := []byte{mainPrefix} - path = append(path, symbol[:]...) - _, enc := c.iavl.Get(path) - if len(enc) == 0 { - return nil - } - - coin := &Model{} - if err := rlp.DecodeBytes(enc, coin); err != nil { - panic(fmt.Sprintf("failed to decode coin at %s: %s", symbol.String(), err)) - } - - coin.symbol = symbol - coin.markDirty = c.markDirty - - // load info - path = []byte{mainPrefix} - path = append(path, symbol[:]...) - path = append(path, infoPrefix) - _, enc = c.iavl.Get(path) - if len(enc) != 0 { - var info Info - if err := rlp.DecodeBytes(enc, &info); err != nil { - panic(fmt.Sprintf("failed to decode coin info %s: %s", symbol.String(), err)) - } - - coin.info = &info - } - - c.setToMap(symbol, coin) - - return coin -} - -func (c *Coins) markDirty(symbol types.CoinSymbol) { - c.dirty[symbol] = struct{}{} -} - -func (c *Coins) getOrderedDirtyCoins() []types.CoinSymbol { - keys := make([]types.CoinSymbol, 0, len(c.dirty)) - for k := range c.dirty { - keys = append(keys, k) - } - - sort.SliceStable(keys, func(i, j int) bool { - return bytes.Compare(keys[i].Bytes(), keys[j].Bytes()) == 1 - }) - - return keys -} - -func (c *Coins) Export(state *types.AppState) map[types.CoinSymbol]types.Coin { - var coins []types.Coin - - if len(state.Coins) != 0 { - for k, coin := range state.Coins { - // check coins' volume - volume := big.NewInt(0) - for _, ff := range state.FrozenFunds { - if ff.Coin == coin.ID { - volume.Add(volume, helpers.StringToBigInt(ff.Value)) - } - } - - for _, candidate := range state.Candidates { - for _, stake := range candidate.Stakes { - if stake.Coin == coin.ID { - volume.Add(volume, helpers.StringToBigInt(stake.Value)) - } - } - - for _, stake := range candidate.Updates { - if stake.Coin == coin.ID { - volume.Add(volume, helpers.StringToBigInt(stake.Value)) - } - } - } - - for _, account := range state.Accounts { - for _, bal := range account.Balance { - if bal.Coin == coin.ID { - volume.Add(volume, helpers.StringToBigInt(bal.Value)) - } - } - } - - state.Coins[k].Volume = volume.String() - } - - return nil - } - - c.iavl.Iterate(func(key []byte, value []byte) bool { - if key[0] == mainPrefix { - if len(key[1:]) > types.CoinSymbolLength { - return false - } - - coinSymbol := types.StrToCoinSymbol(string(key[1:])) - coin := c.GetCoin(coinSymbol) - - coinModel := types.Coin{ - Name: coin.Name(), - Symbol: coin.Symbol(), - Volume: coin.Volume().String(), - Crr: uint64(coin.Crr()), - Reserve: coin.Reserve().String(), - MaxSupply: coin.MaxSupply().String(), - Version: 0, - } - - coins = append(coins, coinModel) - } - - return false - }) - - sort.Slice(coins[:], func(i, j int) bool { - return helpers.StringToBigInt(coins[i].Reserve).Cmp(helpers.StringToBigInt(coins[j].Reserve)) == 1 - }) - - coinsMap := make(map[types.CoinSymbol]types.Coin, len(coins)) - coinsMap[types.GetBaseCoin()] = types.Coin{ID: uint64(types.GetBaseCoinID())} - - for i := range coins { - coins[i].ID = uint64(i + 1) - coinsMap[coins[i].Symbol] = coins[i] - } - - state.Coins = coins - - return coinsMap -} - -func (c *Coins) getFromMap(symbol types.CoinSymbol) *Model { - c.lock.RLock() - defer c.lock.RUnlock() - - return c.list[symbol] -} - -func (c *Coins) setToMap(symbol types.CoinSymbol, model *Model) { - c.lock.Lock() - defer c.lock.Unlock() - - c.list[symbol] = model -} diff --git a/legacy/coins/model.go b/legacy/coins/model.go deleted file mode 100644 index 262fc1146..000000000 --- a/legacy/coins/model.go +++ /dev/null @@ -1,107 +0,0 @@ -package coins - -import ( - "fmt" - "github.com/MinterTeam/minter-go-node/core/types" - "github.com/MinterTeam/minter-go-node/helpers" - "math/big" -) - -var minCoinReserve = helpers.BipToPip(big.NewInt(10000)) - -type Model struct { - CName string - CCrr uint - CMaxSupply *big.Int - - symbol types.CoinSymbol - info *Info - markDirty func(symbol types.CoinSymbol) - isDirty bool -} - -func (m Model) Name() string { - return m.CName -} - -func (m Model) Symbol() types.CoinSymbol { - return m.symbol -} - -func (m Model) Crr() uint { - return m.CCrr -} - -func (m Model) Volume() *big.Int { - return big.NewInt(0).Set(m.info.Volume) -} - -func (m Model) Reserve() *big.Int { - return big.NewInt(0).Set(m.info.Reserve) -} - -func (m *Model) SubVolume(amount *big.Int) { - m.info.Volume.Sub(m.info.Volume, amount) - m.markDirty(m.symbol) - m.info.isDirty = true -} - -func (m *Model) AddVolume(amount *big.Int) { - m.info.Volume.Add(m.info.Volume, amount) - m.markDirty(m.symbol) - m.info.isDirty = true -} - -func (m *Model) SubReserve(amount *big.Int) { - m.info.Reserve.Sub(m.info.Reserve, amount) - m.markDirty(m.symbol) - m.info.isDirty = true -} - -func (m *Model) AddReserve(amount *big.Int) { - m.info.Reserve.Add(m.info.Reserve, amount) - m.markDirty(m.symbol) - m.info.isDirty = true -} - -func (m *Model) SetReserve(reserve *big.Int) { - m.info.Reserve.Set(reserve) - m.markDirty(m.symbol) - m.info.isDirty = true -} - -func (m *Model) SetVolume(volume *big.Int) { - m.info.Volume.Set(volume) - m.markDirty(m.symbol) - m.info.isDirty = true -} - -func (m *Model) CheckReserveUnderflow(delta *big.Int) error { - total := big.NewInt(0).Sub(m.Reserve(), delta) - - if total.Cmp(minCoinReserve) == -1 { - min := big.NewInt(0).Add(minCoinReserve, delta) - return fmt.Errorf("coin %s reserve is too small (%s, required at least %s)", m.symbol.String(), m.Reserve().String(), min.String()) - } - - return nil -} - -func (m Model) IsInfoDirty() bool { - return m.info.isDirty -} - -func (m Model) IsDirty() bool { - return m.isDirty -} - -func (m Model) MaxSupply() *big.Int { - return m.CMaxSupply -} - -type Info struct { - Volume *big.Int - Reserve *big.Int - - isDirty bool -} diff --git a/legacy/frozenfunds/frozen_funds.go b/legacy/frozenfunds/frozen_funds.go deleted file mode 100644 index d184c789c..000000000 --- a/legacy/frozenfunds/frozen_funds.go +++ /dev/null @@ -1,115 +0,0 @@ -package frozenfunds - -import ( - "encoding/binary" - "fmt" - "github.com/MinterTeam/minter-go-node/core/state/bus" - "github.com/MinterTeam/minter-go-node/core/state/candidates" - "github.com/MinterTeam/minter-go-node/core/types" - "github.com/MinterTeam/minter-go-node/rlp" - "github.com/MinterTeam/minter-go-node/tree" - "sort" - "sync" -) - -const mainPrefix = byte('f') - -type RFrozenFunds interface { - Export(state *types.AppState, height uint64) -} - -type FrozenFunds struct { - list map[uint64]*Model - dirty map[uint64]interface{} - - bus *bus.Bus - iavl tree.MTree - - lock sync.RWMutex -} - -func NewFrozenFunds(stateBus *bus.Bus, iavl tree.MTree) (*FrozenFunds, error) { - frozenfunds := &FrozenFunds{bus: stateBus, iavl: iavl, list: map[uint64]*Model{}, dirty: map[uint64]interface{}{}} - return frozenfunds, nil -} - -func (f *FrozenFunds) get(height uint64) *Model { - if ff := f.getFromMap(height); ff != nil { - return ff - } - - _, enc := f.iavl.Get(getPath(height)) - if len(enc) == 0 { - return nil - } - - ff := &Model{} - if err := rlp.DecodeBytes(enc, ff); err != nil { - panic(fmt.Sprintf("failed to decode frozen funds at height %d: %s", height, err)) - } - - ff.height = height - ff.markDirty = f.markDirty - - f.setToMap(height, ff) - - return ff -} - -func (f *FrozenFunds) markDirty(height uint64) { - f.dirty[height] = struct{}{} -} - -func (f *FrozenFunds) getOrderedDirty() []uint64 { - keys := make([]uint64, 0, len(f.dirty)) - for k := range f.dirty { - keys = append(keys, k) - } - - sort.SliceStable(keys, func(i, j int) bool { - return keys[i] < keys[j] - }) - - return keys -} - -func (f *FrozenFunds) Export(state *types.AppState, height uint64, coinsMap map[types.CoinSymbol]types.Coin, candidatesMap map[types.Pubkey]uint32) { - for i := height; i <= height+candidates.UnbondPeriod; i++ { - frozenFunds := f.get(i) - if frozenFunds == nil { - continue - } - - for _, frozenFund := range frozenFunds.List { - state.FrozenFunds = append(state.FrozenFunds, types.FrozenFund{ - Height: i - height, - Address: frozenFund.Address, - CandidateKey: frozenFund.CandidateKey, - CandidateID: uint64(candidatesMap[*frozenFund.CandidateKey]), - Coin: coinsMap[frozenFund.Coin].ID, - Value: frozenFund.Value.String(), - }) - } - } -} - -func (f *FrozenFunds) getFromMap(height uint64) *Model { - f.lock.RLock() - defer f.lock.RUnlock() - - return f.list[height] -} - -func (f *FrozenFunds) setToMap(height uint64, model *Model) { - f.lock.Lock() - defer f.lock.Unlock() - - f.list[height] = model -} - -func getPath(height uint64) []byte { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, height) - - return append([]byte{mainPrefix}, b...) -} diff --git a/legacy/frozenfunds/model.go b/legacy/frozenfunds/model.go deleted file mode 100644 index 826effb1a..000000000 --- a/legacy/frozenfunds/model.go +++ /dev/null @@ -1,40 +0,0 @@ -package frozenfunds - -import ( - "github.com/MinterTeam/minter-go-node/core/types" - "math/big" -) - -type Item struct { - Address types.Address - CandidateKey *types.Pubkey - Coin types.CoinSymbol - Value *big.Int -} - -type Model struct { - List []Item - - height uint64 - deleted bool - markDirty func(height uint64) -} - -func (m *Model) delete() { - m.deleted = true - m.markDirty(m.height) -} - -func (m *Model) addFund(address types.Address, pubkey types.Pubkey, coin types.CoinSymbol, value *big.Int) { - m.List = append(m.List, Item{ - Address: address, - CandidateKey: &pubkey, - Coin: coin, - Value: value, - }) - m.markDirty(m.height) -} - -func (m *Model) Height() uint64 { - return m.height -}