Skip to content

Commit

Permalink
feat: apply oracle commission (#541)
Browse files Browse the repository at this point in the history
  • Loading branch information
gyuguen committed Dec 12, 2022
1 parent df84689 commit d04fd39
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 15 deletions.
19 changes: 17 additions & 2 deletions x/datadeal/keeper/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ func (k Keeper) SubmitConsent(ctx sdk.Context, cert *types.Certificate) error {
return sdkerrors.Wrapf(types.ErrSubmitConsent, err.Error())
}

if err := k.oracleKeeper.VerifyOracle(ctx, unsignedCert.OracleAddress); err != nil {
return sdkerrors.Wrapf(types.ErrSubmitConsent, err.Error())
}

deal, err := k.GetDeal(ctx, unsignedCert.DealId)
if err != nil {
return sdkerrors.Wrapf(types.ErrSubmitConsent, "failed to get deal. %v", err)
Expand Down Expand Up @@ -64,12 +68,23 @@ func (k Keeper) sendReward(ctx sdk.Context, deal *types.Deal, unsignedCert *type
return fmt.Errorf("not enough balance in deal")
}

// TODO calculate oracle commission
oracle, err := k.oracleKeeper.GetOracle(ctx, unsignedCert.OracleAddress)
if err != nil {
return fmt.Errorf("failed to get oracle. %w", err)
}
oracleCommissionRate := oracle.OracleCommissionRate

providerReward := sdk.NewCoin(assets.MicroMedDenom, pricePerData.TruncateInt())
oracleReward := sdk.NewCoin(assets.MicroMedDenom, pricePerData.Mul(oracleCommissionRate).TruncateInt())
providerReward := sdk.NewCoin(assets.MicroMedDenom, pricePerData.Mul(sdk.OneDec().Sub(oracleCommissionRate)).TruncateInt())
if err := k.bankKeeper.SendCoins(ctx, dealAccAddr, providerAccAddr, sdk.NewCoins(providerReward)); err != nil {
return fmt.Errorf("failed to send reward to provider. %w", err)
}

// We already do oracle address verification above.
oracleAccAddr, _ := sdk.AccAddressFromBech32(unsignedCert.OracleAddress)
if err := k.bankKeeper.SendCoins(ctx, dealAccAddr, oracleAccAddr, sdk.NewCoins(oracleReward)); err != nil {
return fmt.Errorf("failed to send reward to oracle. %w", err)
}
return nil
}

Expand Down
106 changes: 103 additions & 3 deletions x/datadeal/keeper/certificate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper_test

import (
"encoding/base64"
"fmt"
"testing"

"github.com/btcsuite/btcd/btcec"
Expand All @@ -17,6 +18,8 @@ import (
type certificateTestSuite struct {
dealTestSuite

uniqueID string

oracleAccPrivKey cryptotypes.PrivKey
oracleAccPubKey cryptotypes.PubKey
oracleAccAddr sdk.AccAddress
Expand All @@ -41,6 +44,7 @@ func (suite *certificateTestSuite) BeforeTest(_, _ string) {
suite.consumerAccAddr = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
suite.defaultFunds = sdk.NewCoins(sdk.NewCoin(assets.MicroMedDenom, sdk.NewInt(10000000000)))

suite.uniqueID = "uniqueID"
suite.oracleAccPrivKey = secp256k1.GenPrivKey()
suite.oracleAccPubKey = suite.oracleAccPrivKey.PubKey()
suite.oracleAccAddr = sdk.AccAddress(suite.oracleAccPubKey.Address())
Expand All @@ -59,7 +63,7 @@ func (suite *certificateTestSuite) BeforeTest(_, _ string) {
suite.OracleKeeper.SetParams(suite.Ctx, oracletypes.Params{
OraclePublicKey: base64.StdEncoding.EncodeToString(suite.oraclePubKey.SerializeCompressed()),
OraclePubKeyRemoteReport: "",
UniqueId: "",
UniqueId: suite.uniqueID,
})

err := suite.DataDealKeeper.SetNextDealNumber(suite.Ctx, 1)
Expand All @@ -85,12 +89,28 @@ func (suite *certificateTestSuite) createSampleDeal(budgetAmount, maxNumData uin
return dealID
}

func (suite *certificateTestSuite) storeSampleOracle(address, uniqueID string, commissionRate sdk.Dec) *oracletypes.Oracle {
oracle := &oracletypes.Oracle{
OracleAddress: address,
UniqueId: uniqueID,
Endpoint: "https://my-validator.org",
OracleCommissionRate: commissionRate,
}
err := suite.OracleKeeper.SetOracle(suite.Ctx, oracle)
suite.Require().NoError(err)

return oracle
}

func (suite *certificateTestSuite) TestSubmitConsentSuccess() {
budgetAmount := uint64(10000)
dealID := suite.createSampleDeal(budgetAmount, 10)
deal, err := suite.DataDealKeeper.GetDeal(suite.Ctx, dealID)
suite.Require().NoError(err)

oracleCommissionRate := sdk.NewDecWithPrec(1, 1) // 10%
suite.storeSampleOracle(suite.oracleAccAddr.String(), suite.uniqueID, oracleCommissionRate)

unsignedCert := &types.UnsignedCertificate{
Cid: "cid",
OracleAddress: suite.oracleAccAddr.String(),
Expand All @@ -114,6 +134,9 @@ func (suite *certificateTestSuite) TestSubmitConsentSuccess() {
providerBalance := suite.BankKeeper.GetBalance(suite.Ctx, suite.providerAccAddr, assets.MicroMedDenom)
suite.Require().Equal(sdk.ZeroInt(), providerBalance.Amount)

oracleBalance := suite.BankKeeper.GetBalance(suite.Ctx, suite.oracleAccAddr, assets.MicroMedDenom)
suite.Require().Equal(sdk.ZeroInt(), oracleBalance.Amount)

dealAccAddr, err := sdk.AccAddressFromBech32(deal.Address)
suite.Require().NoError(err)
dealBalance := suite.BankKeeper.GetBalance(suite.Ctx, dealAccAddr, assets.MicroMedDenom)
Expand All @@ -123,7 +146,10 @@ func (suite *certificateTestSuite) TestSubmitConsentSuccess() {
suite.Require().NoError(err)

providerBalance = suite.BankKeeper.GetBalance(suite.Ctx, suite.providerAccAddr, assets.MicroMedDenom)
suite.Require().Equal(sdk.NewInt(1000), providerBalance.Amount)
suite.Require().Equal(sdk.NewInt(900), providerBalance.Amount)

oracleBalance = suite.BankKeeper.GetBalance(suite.Ctx, suite.oracleAccAddr, assets.MicroMedDenom)
suite.Require().Equal(sdk.NewInt(100), oracleBalance.Amount)

dealAccAddr, err = sdk.AccAddressFromBech32(deal.Address)
suite.Require().NoError(err)
Expand All @@ -142,6 +168,9 @@ func (suite *certificateTestSuite) TestSubmitConsentChangeStatusComplete() {
deal, err := suite.DataDealKeeper.GetDeal(suite.Ctx, dealID)
suite.Require().NoError(err)

oracleCommissionRate := sdk.NewDecWithPrec(1, 1) // 10%
suite.storeSampleOracle(suite.oracleAccAddr.String(), suite.uniqueID, oracleCommissionRate)

unsignedCert := &types.UnsignedCertificate{
Cid: "cid",
OracleAddress: suite.oracleAccAddr.String(),
Expand All @@ -164,6 +193,9 @@ func (suite *certificateTestSuite) TestSubmitConsentChangeStatusComplete() {
providerBalance := suite.BankKeeper.GetBalance(suite.Ctx, suite.providerAccAddr, assets.MicroMedDenom)
suite.Require().Equal(sdk.ZeroInt(), providerBalance.Amount)

oracleBalance := suite.BankKeeper.GetBalance(suite.Ctx, suite.oracleAccAddr, assets.MicroMedDenom)
suite.Require().Equal(sdk.ZeroInt(), oracleBalance.Amount)

dealAccAddr, err := sdk.AccAddressFromBech32(deal.Address)
suite.Require().NoError(err)
dealBalance := suite.BankKeeper.GetBalance(suite.Ctx, dealAccAddr, assets.MicroMedDenom)
Expand All @@ -173,7 +205,10 @@ func (suite *certificateTestSuite) TestSubmitConsentChangeStatusComplete() {
suite.Require().NoError(err)

providerBalance = suite.BankKeeper.GetBalance(suite.Ctx, suite.providerAccAddr, assets.MicroMedDenom)
suite.Require().Equal(sdk.NewInt(10000), providerBalance.Amount)
suite.Require().Equal(sdk.NewInt(9000), providerBalance.Amount)

oracleBalance = suite.BankKeeper.GetBalance(suite.Ctx, suite.oracleAccAddr, assets.MicroMedDenom)
suite.Require().Equal(sdk.NewInt(1000), oracleBalance.Amount)

dealAccAddr, err = sdk.AccAddressFromBech32(deal.Address)
suite.Require().NoError(err)
Expand All @@ -186,10 +221,72 @@ func (suite *certificateTestSuite) TestSubmitConsentChangeStatusComplete() {
suite.Require().Equal(types.DEAL_STATUS_COMPLETED, deal.Status)
}

func (suite *certificateTestSuite) TestSubmitConsentNotRegisteredOracle() {
budgetAmount := uint64(10000)
dealID := suite.createSampleDeal(budgetAmount, 1)

unsignedCert := &types.UnsignedCertificate{
Cid: "cid",
OracleAddress: suite.providerAccAddr.String(),
DealId: dealID,
ProviderAddress: suite.providerAccAddr.String(),
DataHash: suite.dataHash,
}

unsignedCertBz, err := unsignedCert.Marshal()
suite.Require().NoError(err)

sign, err := suite.oraclePrivKey.Sign(unsignedCertBz)
suite.Require().NoError(err)

certificate := &types.Certificate{
UnsignedCertificate: unsignedCert,
Signature: sign.Serialize(),
}

err = suite.DataDealKeeper.SubmitConsent(suite.Ctx, certificate)
suite.Require().ErrorIs(err, types.ErrSubmitConsent)
suite.Require().ErrorContains(err, fmt.Sprintf("failed to oracle validation. address(%s)", suite.providerAccAddr.String()))
}

func (suite *certificateTestSuite) TestSubmitConsentNotSameUniqueID() {
budgetAmount := uint64(10000)
dealID := suite.createSampleDeal(budgetAmount, 1)

oracleCommissionRate := sdk.NewDecWithPrec(1, 1) // 10%
suite.storeSampleOracle(suite.oracleAccAddr.String(), "invalidUniqueID", oracleCommissionRate)

unsignedCert := &types.UnsignedCertificate{
Cid: "cid",
OracleAddress: suite.oracleAccAddr.String(),
DealId: dealID,
ProviderAddress: suite.providerAccAddr.String(),
DataHash: suite.dataHash,
}

unsignedCertBz, err := unsignedCert.Marshal()
suite.Require().NoError(err)

sign, err := suite.oraclePrivKey.Sign(unsignedCertBz)
suite.Require().NoError(err)

certificate := &types.Certificate{
UnsignedCertificate: unsignedCert,
Signature: sign.Serialize(),
}

err = suite.DataDealKeeper.SubmitConsent(suite.Ctx, certificate)
suite.Require().ErrorIs(err, types.ErrSubmitConsent)
suite.Require().ErrorContains(err, "is not active an oracle.")
}

func (suite *certificateTestSuite) TestSubmitConsentInvalidSignature() {
budgetAmount := uint64(10000)
dealID := suite.createSampleDeal(budgetAmount, 1)

oracleCommissionRate := sdk.NewDecWithPrec(1, 1) // 10%
suite.storeSampleOracle(suite.oracleAccAddr.String(), suite.uniqueID, oracleCommissionRate)

unsignedCert := &types.UnsignedCertificate{
Cid: "cid",
OracleAddress: suite.oracleAccAddr.String(),
Expand All @@ -215,6 +312,9 @@ func (suite *certificateTestSuite) TestSubmitConsentInvalidSignature() {
}

func (suite *certificateTestSuite) TestSubmitConsentNotExistDeal() {
oracleCommissionRate := sdk.NewDecWithPrec(1, 1) // 10%
suite.storeSampleOracle(suite.oracleAccAddr.String(), suite.uniqueID, oracleCommissionRate)

unsignedCert := &types.UnsignedCertificate{
Cid: "cid",
OracleAddress: suite.oracleAccAddr.String(),
Expand Down
20 changes: 19 additions & 1 deletion x/oracle/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,22 @@ func (k Keeper) VerifyOracleSignature(ctx sdk.Context, msg codec.ProtoMarshaler,
}

return nil
}
}

func (k Keeper) VerifyOracle(ctx sdk.Context, oracleAddress string) error {
oracle, err := k.GetOracle(ctx, oracleAddress)
if err != nil {
return fmt.Errorf("failed to oracle validation. address(%s) %w", oracleAddress, err)
}

activeUniqueID := k.GetParams(ctx).UniqueId
if activeUniqueID != oracle.UniqueId {
return fmt.Errorf("is not active an oracle. oracleAddress(%s), oracleUniqueID(%s), activeUniqueID(%s)",
oracle.OracleAddress,
oracle.UniqueId,
activeUniqueID,
)
}

return nil
}
18 changes: 9 additions & 9 deletions x/oracle/types/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ func (p *Params) Validate() error {
return nil
}

func mustDecodeBase64Str(s string) []byte {
decoded, err := base64.StdEncoding.DecodeString(s)
if err != nil {
panic(err)
}
return decoded
}

func validateOraclePublicKey(i interface{}) error {
pubKeyBase64, ok := i.(string)
if !ok {
Expand Down Expand Up @@ -98,12 +106,4 @@ func validateUniqueID(i interface{}) error {
// It panics if the decoding is failed, assuming that the Params was already validated by Params.Validate().
func (p Params) MustDecodeOraclePublicKey() []byte {
return mustDecodeBase64Str(p.OraclePublicKey)
}

func mustDecodeBase64Str(s string) []byte {
decoded, err := base64.StdEncoding.DecodeString(s)
if err != nil {
panic(err)
}
return decoded
}
}

0 comments on commit d04fd39

Please sign in to comment.