Skip to content

Commit

Permalink
starting v2 (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
DefinitelyNotAGoat authored Mar 4, 2020
1 parent 7a014d7 commit 07b7aa3
Show file tree
Hide file tree
Showing 776 changed files with 91,333 additions and 120,153 deletions.
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

# Change Log
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## v2.0.0-alpha

### changed
- Rebranded payman into tzpay
- project structure
- added tests
- uses go-tezos v2.5.2-alpha
- forges operations locally
- uses enviroment variables for configuration
- docker image

13 changes: 13 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM golang:latest

# Set the Current Working Directory inside the container
WORKDIR $GOPATH/src/github.com/goat-systems/tzpay

# Copy everything from the current directory to the PWD (Present Working Directory) inside the container
COPY . .

# Download all the dependencies
RUN go get -d -v ./...

# Install the package
RUN go install -v ./...
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
PROJECT_NAME := "payman"
PROJECT_NAME := "tzpay"
VERSION := "v2.0.0"
PKG := "github.com/goat-systems/$(PROJECT_NAME)"
PKG_LIST := $(shell go list ${PKG}/... | grep -v /vendor/)
Expand Down Expand Up @@ -27,6 +27,9 @@ dep: ## Get the dependencies
@go get -u golang.org/x/lint/golint
@go get -u honnef.co/go/tools/...

build: ## Get the dependencies
@go build

clean: ## Remove previous build
@rm -f $(PROJECT_NAME)

Expand Down
431 changes: 261 additions & 170 deletions README.md

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion _config.yml

This file was deleted.

247 changes: 247 additions & 0 deletions cli/internal/baker/baker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
package baker

import (
"context"
"math/big"
"unicode"

gotezos "github.com/goat-systems/go-tezos/v2"
"github.com/goat-systems/tzpay/v2/cli/internal/enviroment"
"github.com/pkg/errors"
)

// DelegationEarning -
type DelegationEarning struct {
Delegation string
Fee *big.Int
GrossRewards *big.Int
NetRewards *big.Int
Share float64
}

// Baker is a tezos baker that can get payouts and execute them.
type Baker struct {
gt gotezos.IFace
}

type processDelegationsInput struct {
delegations *[]string
stakingBalance *big.Int
frozenBalanceRewards *gotezos.FrozenBalance
blockHash string
}

type processDelegationsOutput struct {
delegationEarning DelegationEarning
err error
}

type processDelegationInput struct {
delegation string
stakingBalance *big.Int
frozenBalanceRewards *gotezos.FrozenBalance
blockHash string
}

// Payout contains all needed information for a payout
type Payout struct {
DelegationEarnings DelegationEarnings `json:"delegaions"`
Cycle int `json:"cycle"`
FrozenBalance *big.Int `json:"rewards"`
StakingBalance *big.Int `json:"staking_balance"`
Delegate string `json:"delegate"`
}

// DelegationEarnings contains list of DelegationEarning and implements sort.
type DelegationEarnings []DelegationEarning

func (d DelegationEarnings) Len() int { return len(d) }
func (d DelegationEarnings) Swap(i, j int) {
d[i], d[j] = d[j], d[i]
}

func (d DelegationEarnings) Less(i, j int) bool {
iRunes := []rune(d[i].Delegation)
jRunes := []rune(d[j].Delegation)

max := len(iRunes)
if max > len(jRunes) {
max = len(jRunes)
}

for idx := 0; idx < max; idx++ {
ir := iRunes[idx]
jr := jRunes[idx]

lir := unicode.ToLower(ir)
ljr := unicode.ToLower(jr)

if lir != ljr {
return lir < ljr
}

if ir != jr {
return ir < jr
}
}

return false
}

// NewBaker returns a pointer to a new Baker
func NewBaker(gt gotezos.IFace) *Baker {
return &Baker{gt: gt}
}

// Payouts returns all payouts for a cycle
func (b *Baker) Payouts(ctx context.Context, cycle int) (*Payout, error) {
params := enviroment.GetEnviromentFromContext(ctx)
frozenBalanceRewards, err := b.gt.FrozenBalance(cycle, params.Delegate)
if err != nil {
return nil, errors.Wrapf(err, "failed to get delegation earnings for cycle %d", cycle)
}

delegations, err := b.gt.DelegatedContractsAtCycle(cycle, params.Delegate)
if err != nil {
return nil, errors.Wrapf(err, "failed to get delegation earnings for cycle %d", cycle)
}

networkCycle, err := b.gt.Cycle(cycle)
if err != nil {
return nil, errors.Wrapf(err, "failed to get delegation earnings for cycle %d", cycle)
}

stakingBalance, err := b.gt.StakingBalance(networkCycle.BlockHash, params.Delegate)
if err != nil {
return nil, errors.Wrapf(err, "failed to get delegation earnings for cycle %d", cycle)
}

out := b.proccessDelegations(ctx, &processDelegationsInput{
delegations: delegations,
stakingBalance: stakingBalance,
frozenBalanceRewards: frozenBalanceRewards,
blockHash: networkCycle.BlockHash,
})

payouts := Payout{
Delegate: params.Delegate,
StakingBalance: stakingBalance,
Cycle: cycle,
FrozenBalance: frozenBalanceRewards.Rewards.Big,
}
for _, delegation := range out {
if delegation.err != nil {
err = errors.Wrapf(delegation.err, "failed to get payout for delegation %s", delegation.delegationEarning.Delegation)
} else {
payouts.DelegationEarnings = append(payouts.DelegationEarnings, delegation.delegationEarning)
}
}

return &payouts, err
}

func (b *Baker) proccessDelegations(ctx context.Context, input *processDelegationsInput) []processDelegationsOutput {
numJobs := len(*input.delegations)
jobs := make(chan processDelegationInput, numJobs)
results := make(chan processDelegationsOutput, numJobs)

for i := 0; i < 50; i++ {
go b.proccessDelegationWorker(ctx, jobs, results)
}

for _, pd := range *input.delegations {
jobs <- processDelegationInput{
delegation: pd,
stakingBalance: input.stakingBalance,
frozenBalanceRewards: input.frozenBalanceRewards,
blockHash: input.blockHash,
}
}
close(jobs)

var out []processDelegationsOutput
for i := 1; i <= numJobs; i++ {
out = append(out, <-results)
}
close(results)

return out
}

func (b *Baker) proccessDelegationWorker(ctx context.Context, jobs <-chan processDelegationInput, results chan<- processDelegationsOutput) {
for j := range jobs {
d, err := b.processDelegation(ctx, &j)
if err != nil {
results <- processDelegationsOutput{
err: err,
}
} else {
results <- processDelegationsOutput{
delegationEarning: *d,
}
}
}
}

func (b *Baker) processDelegation(ctx context.Context, input *processDelegationInput) (*DelegationEarning, error) {
params := enviroment.GetEnviromentFromContext(ctx)
delegationEarning := &DelegationEarning{Delegation: input.delegation}
balance, err := b.gt.Balance(input.blockHash, input.delegation)
if err != nil {
return nil, errors.Wrapf(err, "failed to process delegation earnings for delegation %s", input.delegation)
}

delegationEarning.Share = float64(balance.Int64()) / float64(input.stakingBalance.Int64())
grossRewardsFloat := delegationEarning.Share * float64(input.frozenBalanceRewards.Rewards.Big.Int64())
feeFloat := grossRewardsFloat * params.BakersFee

delegationEarning.GrossRewards = big.NewInt(int64(grossRewardsFloat))
delegationEarning.Fee = big.NewInt(int64(feeFloat))
delegationEarning.NetRewards = big.NewInt(0).Sub(delegationEarning.GrossRewards, delegationEarning.Fee)

return delegationEarning, nil
}

// ForgePayout converts Payout into operation contents and forges them locally
func (b *Baker) ForgePayout(ctx context.Context, payout Payout) (string, error) {
base := enviroment.GetEnviromentFromContext(ctx)
head, err := b.gt.Head()
if err != nil {
return "", errors.Wrap(err, "failed to forge payout")
}

counter, err := b.gt.Counter(head.Hash, base.Wallet.Address)
if err != nil {
return "", errors.Wrap(err, "failed to forge payout")
}

transactions := b.constructPayoutContents(ctx, *counter, payout)

forge, err := gotezos.ForgeTransactionOperation(head.Hash, transactions...)
if err != nil {
return "", errors.Wrap(err, "failed to forge payout")
}

return *forge, nil
}

func (b *Baker) constructPayoutContents(ctx context.Context, counter int, payout Payout) []gotezos.ForgeTransactionOperationInput {
base := enviroment.GetEnviromentFromContext(ctx)
var contents []gotezos.ForgeTransactionOperationInput
for _, delegation := range payout.DelegationEarnings {
counter++
if delegation.NetRewards.Int64() >= int64(base.MinimumPayment) {
contents = append(contents, gotezos.ForgeTransactionOperationInput{
Source: base.Wallet.Address,
Destination: delegation.Delegation,
Amount: gotezos.Int{Big: delegation.NetRewards},
Fee: gotezos.Int{Big: big.NewInt(int64(base.NetworkFee))}, //TODO: expose NewInt function in GoTezos
GasLimit: gotezos.Int{Big: big.NewInt(int64(base.GasLimit))},
Counter: counter,
StorageLimit: gotezos.Int{Big: big.NewInt(int64(0))},
})
}
}

return contents
}
Loading

0 comments on commit 07b7aa3

Please sign in to comment.