forked from TrueCloudLab/frostfs-node
[#360] Implement basic settlement context
Basic settlement context is a main structure that implement logic of basic settlement phases: collecting assets from container owners and then distributing them to storage nodes. Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
parent
f45675b7a2
commit
a624bb881d
3 changed files with 186 additions and 0 deletions
94
pkg/innerring/processors/settlement/basic/collect.go
Normal file
94
pkg/innerring/processors/settlement/basic/collect.go
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
package basic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/settlement/common"
|
||||||
|
"github.com/nspcc-dev/neofs-node/pkg/morph/client/container/wrapper"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
bigGB = big.NewInt(1 << 30)
|
||||||
|
bigZero = big.NewInt(0)
|
||||||
|
bigOne = big.NewInt(1)
|
||||||
|
)
|
||||||
|
|
||||||
|
func (inc *IncomeSettlementContext) Collect() {
|
||||||
|
inc.mu.Lock()
|
||||||
|
defer inc.mu.Unlock()
|
||||||
|
|
||||||
|
// todo: save state of bank wallet
|
||||||
|
|
||||||
|
cachedRate := inc.rate.BasicRate()
|
||||||
|
|
||||||
|
cnrEstimations, err := inc.estimations.Estimations(inc.epoch)
|
||||||
|
if err != nil {
|
||||||
|
inc.log.Warn("can't fetch container size estimations",
|
||||||
|
zap.Uint64("epoch", inc.epoch))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range cnrEstimations {
|
||||||
|
owner, err := inc.container.ContainerInfo(cnrEstimations[i].ContainerID)
|
||||||
|
if err != nil {
|
||||||
|
inc.log.Warn("can't fetch container info",
|
||||||
|
zap.Uint64("epoch", inc.epoch),
|
||||||
|
zap.Stringer("container_id", cnrEstimations[i].ContainerID))
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
cnrNodes, err := inc.placement.ContainerNodes(inc.epoch, cnrEstimations[i].ContainerID)
|
||||||
|
if err != nil {
|
||||||
|
inc.log.Debug("can't fetch container info",
|
||||||
|
zap.Uint64("epoch", inc.epoch),
|
||||||
|
zap.Stringer("container_id", cnrEstimations[i].ContainerID))
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
avg := inc.avgEstimation(cnrEstimations[i]) // average container size per node
|
||||||
|
total := calculateBasicSum(avg, cachedRate, len(cnrNodes))
|
||||||
|
|
||||||
|
inc.txTable.Transfer(&common.TransferTx{
|
||||||
|
From: owner.Owner(),
|
||||||
|
To: inc.bankOwner,
|
||||||
|
Amount: total,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
common.TransferAssets(inc.exchange, inc.txTable)
|
||||||
|
}
|
||||||
|
|
||||||
|
// avgEstimation returns estimation value for single container. Right now it
|
||||||
|
// simply calculates average of all announcements, however it can be smarter and
|
||||||
|
// base result on reputation of announcers and clever math.
|
||||||
|
func (inc *IncomeSettlementContext) avgEstimation(e *wrapper.Estimations) (avg uint64) {
|
||||||
|
if len(e.Values) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range e.Values {
|
||||||
|
avg += e.Values[i].Size
|
||||||
|
}
|
||||||
|
|
||||||
|
return avg / uint64(len(e.Values))
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculateBasicSum(size, rate uint64, ln int) *big.Int {
|
||||||
|
bigRate := big.NewInt(int64(rate))
|
||||||
|
|
||||||
|
total := size * uint64(ln)
|
||||||
|
|
||||||
|
price := new(big.Int).SetUint64(total)
|
||||||
|
price.Mul(price, bigRate)
|
||||||
|
price.Div(price, bigGB)
|
||||||
|
|
||||||
|
if price.Cmp(bigZero) == 0 {
|
||||||
|
price.Add(price, bigOne)
|
||||||
|
}
|
||||||
|
|
||||||
|
return price
|
||||||
|
}
|
86
pkg/innerring/processors/settlement/basic/context.go
Normal file
86
pkg/innerring/processors/settlement/basic/context.go
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
package basic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/mr-tron/base58"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/pkg/owner"
|
||||||
|
"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/settlement/common"
|
||||||
|
"github.com/nspcc-dev/neofs-node/pkg/morph/client/container/wrapper"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
EstimationFetcher interface {
|
||||||
|
Estimations(uint64) ([]*wrapper.Estimations, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
RateFetcher interface {
|
||||||
|
BasicRate() uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
IncomeSettlementContext struct {
|
||||||
|
mu sync.Mutex // lock to prevent collection and distribution in the same time
|
||||||
|
|
||||||
|
log *zap.Logger
|
||||||
|
epoch uint64
|
||||||
|
|
||||||
|
rate RateFetcher
|
||||||
|
estimations EstimationFetcher
|
||||||
|
container common.ContainerStorage
|
||||||
|
placement common.PlacementCalculator
|
||||||
|
exchange common.Exchanger
|
||||||
|
|
||||||
|
txTable *common.TransferTable
|
||||||
|
bankOwner *owner.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
IncomeSettlementContextPrms struct {
|
||||||
|
Log *zap.Logger
|
||||||
|
Epoch uint64
|
||||||
|
Rate RateFetcher
|
||||||
|
Estimations EstimationFetcher
|
||||||
|
Container common.ContainerStorage
|
||||||
|
Placement common.PlacementCalculator
|
||||||
|
Exchange common.Exchanger
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewIncomeSettlementContext(p *IncomeSettlementContextPrms) (*IncomeSettlementContext, error) {
|
||||||
|
bankingAccount, err := bankOwnerID()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err // should never happen
|
||||||
|
}
|
||||||
|
|
||||||
|
return &IncomeSettlementContext{
|
||||||
|
log: p.Log,
|
||||||
|
epoch: p.Epoch,
|
||||||
|
rate: p.Rate,
|
||||||
|
estimations: p.Estimations,
|
||||||
|
container: p.Container,
|
||||||
|
placement: p.Placement,
|
||||||
|
exchange: p.Exchange,
|
||||||
|
txTable: common.NewTransferTable(),
|
||||||
|
bankOwner: bankingAccount,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func bankOwnerID() (*owner.ID, error) {
|
||||||
|
u := util.Uint160{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // todo: define const
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
|
||||||
|
|
||||||
|
d, err := base58.Decode(address.Uint160ToString(u))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var w owner.NEO3Wallet
|
||||||
|
copy(w[:], d)
|
||||||
|
|
||||||
|
o := owner.NewID()
|
||||||
|
o.SetNeo3Wallet(&w)
|
||||||
|
|
||||||
|
return o, nil
|
||||||
|
}
|
6
pkg/innerring/processors/settlement/basic/distribute.go
Normal file
6
pkg/innerring/processors/settlement/basic/distribute.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package basic
|
||||||
|
|
||||||
|
func (inc *IncomeSettlementContext) Distribute() {
|
||||||
|
inc.mu.Lock()
|
||||||
|
defer inc.mu.Unlock()
|
||||||
|
}
|
Loading…
Reference in a new issue