Skip to content

Commit

Permalink
fix(bidengine): decode script result directly into decint
Browse files Browse the repository at this point in the history
Signed-off-by: Artur Troian <[email protected]>
  • Loading branch information
troian committed Aug 15, 2023
1 parent 285a363 commit 4e5a60f
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 34 deletions.
5 changes: 3 additions & 2 deletions bidengine/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,9 @@ loop:
pricech = runner.Do(metricsutils.ObserveRunner(func() runner.Result {
// Calculate price & bid
priceReq := Request{
Owner: group.GroupID.Owner,
GSpec: &group.GroupSpec,
Owner: group.GroupID.Owner,
GSpec: &group.GroupSpec,
PricePrecision: DefaultPricePrecision,
}
return runner.NewResult(o.cfg.PricingStrategy.CalculatePrice(ctx, priceReq))
}, pricingDuration))
Expand Down
20 changes: 14 additions & 6 deletions bidengine/pricing.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@ import (
)

type Request struct {
Owner string `json:"owner"`
GSpec *dtypes.GroupSpec
Owner string `json:"owner"`
GSpec *dtypes.GroupSpec
PricePrecision int
}

const (
DefaultPricePrecision = 6
)

type BidPricingStrategy interface {
CalculatePrice(ctx context.Context, req Request) (sdk.DecCoin, error)
}
Expand Down Expand Up @@ -106,8 +111,10 @@ func MakeScalePricing(
return result, nil
}

var ErrBidQuantityInvalid = errors.New("A bid quantity is invalid")
var ErrBidZero = errors.New("A bid of zero was produced")
var (
ErrBidQuantityInvalid = errors.New("A bid quantity is invalid")
ErrBidZero = errors.New("A bid of zero was produced")
)

func ceilBigRatToBigInt(v *big.Rat) *big.Int {
numerator := v.Num()
Expand Down Expand Up @@ -344,6 +351,7 @@ type dataForScriptElement struct {
}

type dataForScript struct {
Resources []dataForScriptElement `json:"resources"`
Price string `json:"price"`
Resources []dataForScriptElement `json:"resources"`
Price sdk.DecCoin `json:"price"`
PricePrecision *int `json:"price_precision,omitempty"`
}
18 changes: 11 additions & 7 deletions bidengine/pricing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ import (
"testing"
"time"

"github.com/akash-network/provider/cluster/util"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/shopspring/decimal"
"github.com/stretchr/testify/require"
Expand All @@ -28,6 +26,8 @@ import (
atypes "github.com/akash-network/akash-api/go/node/types/v1beta3"
"github.com/akash-network/node/sdl"
"github.com/akash-network/node/testutil"

"github.com/akash-network/provider/cluster/util"
)

func Test_ScalePricingRejectsAllZero(t *testing.T) {
Expand Down Expand Up @@ -414,7 +414,7 @@ func Test_ScriptPricingFailsWhenScriptExitsWithoutWritingResultToStdout(t *testi
}

_, err = pricing.CalculatePrice(context.Background(), req)
require.Equal(t, io.EOF, errors.Unwrap(err))
require.ErrorIs(t, err, io.EOF)
}

func Test_ScriptPricingFailsWhenScriptWritesZeroResult(t *testing.T) {
Expand Down Expand Up @@ -498,7 +498,7 @@ func Test_ScriptPricingFailsWhenScriptWritesOverflowResult(t *testing.T) {
scriptPath := path.Join(tempdir, "test_script.sh")
fout, err := os.OpenFile(scriptPath, os.O_WRONLY|os.O_CREATE, os.ModePerm)
require.NoError(t, err)
// Write the maximum value, followed by zero so it is 10x
// Write the maximum value, followed by zero, so it is 10x
_, err = fmt.Fprintf(fout, "#!/bin/sh\necho %s0\nexit 0", sdk.MaxSortableDec.String())
require.NoError(t, err)
err = fout.Close()
Expand All @@ -514,7 +514,7 @@ func Test_ScriptPricingFailsWhenScriptWritesOverflowResult(t *testing.T) {
}

_, err = pricing.CalculatePrice(context.Background(), req)
require.Equal(t, ErrBidQuantityInvalid, err)
require.ErrorIs(t, err, ErrBidQuantityInvalid)
}

func Test_ScriptPricingReturnsResultFromScript(t *testing.T) {
Expand Down Expand Up @@ -682,9 +682,10 @@ func Test_ScriptPricingWritesJsonToStdin(t *testing.T) {
func Test_ScriptPricingFromScript(t *testing.T) {
const (
mockAPIResponse = `{"akash-network":{"usd":3.57}}`
expectedPrice = 67843138
)

expectedPrice := fmt.Sprintf("%.*f", DefaultPricePrecision, 67843137.254901960)

server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, err := io.WriteString(w, mockAPIResponse)
Expand All @@ -711,7 +712,10 @@ func Test_ScriptPricingFromScript(t *testing.T) {

price, err := pricing.CalculatePrice(context.Background(), req)
require.NoError(t, err)
require.Equal(t, sdk.NewDecCoin("uakt", sdk.NewInt(expectedPrice)).String(), price.String())
amount, err := sdk.NewDecFromStr(expectedPrice)
require.NoError(t, err)

require.Equal(t, sdk.NewDecCoinFromDec("uakt", amount).String(), price.String())
}

func TestRationalToIntConversion(t *testing.T) {
Expand Down
25 changes: 11 additions & 14 deletions bidengine/shellscript.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"os"
"os/exec"
"strings"
Expand Down Expand Up @@ -118,7 +119,11 @@ func (ssp shellScriptPricing) CalculatePrice(ctx context.Context, req Request) (

dataForScript := &dataForScript{
Resources: make([]dataForScriptElement, len(req.GSpec.Resources)),
Price: req.GSpec.Price().String(),
Price: req.GSpec.Price(),
}

if req.PricePrecision > 0 {
dataForScript.PricePrecision = &req.PricePrecision
}

// iterate over everything & sum it up
Expand Down Expand Up @@ -182,18 +187,14 @@ func (ssp shellScriptPricing) CalculatePrice(ctx context.Context, req Request) (
}

// Decode the result
decoder := json.NewDecoder(outputBuf)
decoder.UseNumber()

var priceNumber json.Number
err = decoder.Decode(&priceNumber)
if err != nil {
return sdk.DecCoin{}, fmt.Errorf("%w: script failure %s", err, stderrBuf.String())
valueStr := strings.TrimSpace(outputBuf.String())
if valueStr == "" {
return sdk.DecCoin{}, fmt.Errorf("bid script must return amount:%w%w", io.EOF, ErrBidQuantityInvalid)
}

price, err := sdk.NewDecFromStr(priceNumber.String())
price, err := sdk.NewDecFromStr(valueStr)
if err != nil {
return sdk.DecCoin{}, ErrBidQuantityInvalid
return sdk.DecCoin{}, fmt.Errorf("%w%w", err, ErrBidQuantityInvalid)
}

if price.IsZero() {
Expand All @@ -204,9 +205,5 @@ func (ssp shellScriptPricing) CalculatePrice(ctx context.Context, req Request) (
return sdk.DecCoin{}, ErrBidQuantityInvalid
}

if !price.LTE(sdk.MaxSortableDec) {
return sdk.DecCoin{}, ErrBidQuantityInvalid
}

return sdk.NewDecCoinFromDec(denom, price), nil
}
9 changes: 4 additions & 5 deletions script/usd_pricing_oracle.sh
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ storage_cost_usd=0
# read the JSON in `stdin` into $script_input
read -r script_input

precision=$(jq -r '.price_precision // 6' <<<"$script_input")

# iterate over all the groups and calculate total quantity of each resource
for group in $(jq -c '.resources[]' <<<"$script_input"); do
count=$(jq '.count' <<<"$group")
Expand Down Expand Up @@ -144,8 +146,5 @@ fi
total_cost_akt=$(bc -l <<<"${total_cost_usd}/${usd_per_akt}")
total_cost_uakt=$(bc -l <<<"${total_cost_akt}*1000000")

# Round upwards to get an integer
total_cost_uakt=$(echo "$total_cost_uakt" | jq 'def ceil: if . | floor == . then . else . + 1.0 | floor end; .|ceil')

# return the price in uAKT
echo "$total_cost_uakt"
# DO NOT INCREASE PRECISION below, it gives varying results during tests on different hosts
printf "%.*f" "$precision" "$total_cost_uakt"

0 comments on commit 4e5a60f

Please sign in to comment.