From a503bfc5eca49d0b86706b2ebf5672895aaec3d9 Mon Sep 17 00:00:00 2001 From: Alexxxxxx <118710506+alexgao001@users.noreply.github.com> Date: Fri, 15 Sep 2023 18:38:12 +0800 Subject: [PATCH 1/8] fix: should check for tx response status code as tx failure might not return err (#179) * if status code is not 0, tx will not be onchain * fix comment * check status code in broadcast tx resp --- client/api_account.go | 6 +++--- client/api_basic.go | 14 +++++++++++--- client/api_bucket.go | 26 +++++++------------------- client/api_challenge.go | 4 ++-- client/api_client.go | 6 +++--- client/api_crosschain.go | 10 +++++----- client/api_distribution.go | 8 ++++---- client/api_feegrant.go | 6 +++--- client/api_object.go | 9 +++------ client/api_payment.go | 6 +++--- client/api_proposal.go | 4 ++-- client/api_sp.go | 6 +++--- client/api_validator.go | 16 ++++++++-------- 13 files changed, 57 insertions(+), 64 deletions(-) diff --git a/client/api_account.go b/client/api_account.go index 768d3a44..2417672b 100644 --- a/client/api_account.go +++ b/client/api_account.go @@ -59,7 +59,7 @@ func (c *client) CreatePaymentAccount(ctx context.Context, address string, txOpt return "", err } msgCreatePaymentAccount := paymentTypes.NewMsgCreatePaymentAccount(accAddress.String()) - tx, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msgCreatePaymentAccount}, &txOption) + tx, err := c.BroadcastTx(ctx, []sdk.Msg{msgCreatePaymentAccount}, &txOption) if err != nil { return "", err } @@ -176,7 +176,7 @@ func (c *client) Transfer(ctx context.Context, toAddress string, amount math.Int return "", err } msgSend := bankTypes.NewMsgSend(c.MustGetDefaultAccount().GetAddress(), toAddr, sdk.Coins{sdk.Coin{Denom: gnfdSdkTypes.Denom, Amount: amount}}) - tx, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msgSend}, &txOption) + tx, err := c.BroadcastTx(ctx, []sdk.Msg{msgSend}, &txOption) if err != nil { return "", err } @@ -203,7 +203,7 @@ func (c *client) MultiTransfer(ctx context.Context, details []types.TransferDeta Inputs: []bankTypes.Input{in}, Outputs: outputs, } - tx, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) + tx, err := c.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) if err != nil { return "", err } diff --git a/client/api_basic.go b/client/api_basic.go index e61a4ba0..4506ba11 100644 --- a/client/api_basic.go +++ b/client/api_basic.go @@ -2,6 +2,7 @@ package client import ( "context" + "fmt" "strings" "time" @@ -41,7 +42,7 @@ type Basic interface { SimulateTx(ctx context.Context, msgs []sdk.Msg, txOpt types.TxOption, opts ...grpc.CallOption) (*tx.SimulateResponse, error) SimulateRawTx(ctx context.Context, txBytes []byte, opts ...grpc.CallOption) (*tx.SimulateResponse, error) - BroadcastTx(ctx context.Context, msgs []sdk.Msg, txOpt types.TxOption, opts ...grpc.CallOption) (*tx.BroadcastTxResponse, error) + BroadcastTx(ctx context.Context, msgs []sdk.Msg, txOpt *types.TxOption, opts ...grpc.CallOption) (*tx.BroadcastTxResponse, error) BroadcastRawTx(ctx context.Context, txBytes []byte, sync bool) (*sdk.TxResponse, error) BroadcastVote(ctx context.Context, vote votepool.Vote) error @@ -207,8 +208,15 @@ func (c *client) WaitForTx(ctx context.Context, hash string) (*ctypes.ResultTx, // BroadcastTx broadcasts a transaction containing the provided messages to the chain. // The function returns a pointer to a BroadcastTxResponse and any error that occurred during the operation. -func (c *client) BroadcastTx(ctx context.Context, msgs []sdk.Msg, txOpt types.TxOption, opts ...grpc.CallOption) (*tx.BroadcastTxResponse, error) { - return c.chainClient.BroadcastTx(ctx, msgs, &txOpt, opts...) +func (c *client) BroadcastTx(ctx context.Context, msgs []sdk.Msg, txOpt *types.TxOption, opts ...grpc.CallOption) (*tx.BroadcastTxResponse, error) { + resp, err := c.chainClient.BroadcastTx(ctx, msgs, txOpt, opts...) + if err != nil { + return nil, err + } + if resp.TxResponse.Code != 0 { + return resp, fmt.Errorf("the tx has failed with response code: %d, codespace:%s", resp.TxResponse.Code, resp.TxResponse.Codespace) + } + return resp, nil } // SimulateTx simulates a transaction containing the provided messages on the chain. diff --git a/client/api_bucket.go b/client/api_bucket.go index 8339b510..bcbe2301 100644 --- a/client/api_bucket.go +++ b/client/api_bucket.go @@ -15,8 +15,6 @@ import ( "strings" "time" - ctypes "github.com/cometbft/cometbft/rpc/core/types" - gnfdsdk "github.com/bnb-chain/greenfield/sdk/types" gnfdTypes "github.com/bnb-chain/greenfield/types" "github.com/bnb-chain/greenfield/types/s3util" @@ -160,27 +158,22 @@ func (c *client) CreateBucket(ctx context.Context, bucketName string, primaryAdd broadcastMode := tx.BroadcastMode_BROADCAST_MODE_SYNC opts.TxOpts = &gnfdsdk.TxOption{Mode: &broadcastMode} } - - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{signedMsg}, opts.TxOpts) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{signedMsg}, opts.TxOpts) if err != nil { return "", err } - - var txnResponse *ctypes.ResultTx txnHash := resp.TxResponse.TxHash if !opts.IsAsyncMode { ctxTimeout, cancel := context.WithTimeout(ctx, types.ContextTimeout) defer cancel() - - txnResponse, err = c.WaitForTx(ctxTimeout, txnHash) + txnResponse, err := c.WaitForTx(ctxTimeout, txnHash) if err != nil { return txnHash, fmt.Errorf("the transaction has been submitted, please check it later:%v", err) } if txnResponse.TxResult.Code != 0 { - return txnHash, fmt.Errorf("the createBucket txn has failed with response code: %d", txnResponse.TxResult.Code) + return txnHash, fmt.Errorf("the createBucket txn has failed with response code: %d, codespace:%s", txnResponse.TxResult.Code, txnResponse.TxResult.Codespace) } } - return txnHash, nil } @@ -609,7 +602,7 @@ func (c *client) BuyQuotaForBucket(ctx context.Context, bucketName string, targe } updateBucketMsg := storageTypes.NewMsgUpdateBucketInfo(c.MustGetDefaultAccount().GetAddress(), bucketName, &targetQuota, paymentAddr, bucketInfo.Visibility) - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{updateBucketMsg}, opt.TxOpts) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{updateBucketMsg}, opt.TxOpts) if err != nil { return "", err } @@ -753,27 +746,22 @@ func (c *client) MigrateBucket(ctx context.Context, bucketName string, opts type opts.TxOpts = &gnfdsdk.TxOption{Mode: &broadcastMode} } - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{signedMsg}, opts.TxOpts) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{signedMsg}, opts.TxOpts) if err != nil { return "", err } - - var txnResponse *ctypes.ResultTx txnHash := resp.TxResponse.TxHash if !opts.IsAsyncMode { ctxTimeout, cancel := context.WithTimeout(ctx, types.ContextTimeout) defer cancel() - - txnResponse, err = c.WaitForTx(ctxTimeout, txnHash) + txnResponse, err := c.WaitForTx(ctxTimeout, txnHash) if err != nil { return txnHash, fmt.Errorf("the transaction has been submitted, please check it later:%v", err) } - if txnResponse.TxResult.Code != 0 { - return txnHash, fmt.Errorf("the createBucket txn has failed with response code: %d", txnResponse.TxResult.Code) + return txnHash, fmt.Errorf("the migrateBucket txn has failed with response code: %d, codespace:%s", txnResponse.TxResult.Code, txnResponse.TxResult.Codespace) } } - return txnHash, nil } diff --git a/client/api_challenge.go b/client/api_challenge.go index d50a7056..de1edad1 100644 --- a/client/api_challenge.go +++ b/client/api_challenge.go @@ -152,7 +152,7 @@ func (c *client) SubmitChallenge(ctx context.Context, challengerAddress, spOpera return nil, err } msg := challengetypes.NewMsgSubmit(challenger, spOperator, bucketName, objectName, randomIndex, segmentIndex) - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) if err != nil { return nil, err } @@ -182,7 +182,7 @@ func (c *client) AttestChallenge(ctx context.Context, submitterAddress, challeng } msg := challengetypes.NewMsgAttest(submitter, challengeId, objectId, spOperatorAddress, voteResult, challengerAddress, voteValidatorSet, VoteAggSignature) - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) if err != nil { return nil, err } diff --git a/client/api_client.go b/client/api_client.go index ef9390b6..2c85fbad 100644 --- a/client/api_client.go +++ b/client/api_client.go @@ -700,7 +700,7 @@ func (c *client) sendPutPolicyTxn(ctx context.Context, msg *storageTypes.MsgPutP return "", err } - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msg}, txOpts) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{msg}, txOpts) if err != nil { return "", err } @@ -716,7 +716,7 @@ func (c *client) sendDelPolicyTxn(ctx context.Context, operator sdk.AccAddress, return "", err } - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{delPolicyMsg}, txOpts) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{delPolicyMsg}, txOpts) if err != nil { return "", err } @@ -729,7 +729,7 @@ func (c *client) sendTxn(ctx context.Context, msg sdk.Msg, opt *gnfdSdkTypes.TxO return "", err } - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msg}, opt) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{msg}, opt) if err != nil { return "", err } diff --git a/client/api_crosschain.go b/client/api_crosschain.go index 469b0187..55077a0d 100644 --- a/client/api_crosschain.go +++ b/client/api_crosschain.go @@ -33,7 +33,7 @@ func (c *client) TransferOut(ctx context.Context, toAddress string, amount math. toAddress, &sdk.Coin{Denom: gnfdSdkTypes.Denom, Amount: amount}, ) - txResp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msgTransferOut}, &txOption) + txResp, err := c.BroadcastTx(ctx, []sdk.Msg{msgTransferOut}, &txOption) if err != nil { return nil, err } @@ -54,7 +54,7 @@ func (c *client) Claims(ctx context.Context, srcShainId, destChainId uint32, seq voteAddrSet, aggSignature) - txResp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) + txResp, err := c.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) if err != nil { return nil, err } @@ -114,7 +114,7 @@ func (c *client) GetCrossChainPackage(ctx context.Context, destChainId sdk.Chain // MirrorGroup mirrors the group to BSC as NFT func (c *client) MirrorGroup(ctx context.Context, destChainId sdk.ChainID, groupId math.Uint, groupName string, txOption gnfdSdkTypes.TxOption) (*sdk.TxResponse, error) { msgMirrorGroup := storagetypes.NewMsgMirrorGroup(c.MustGetDefaultAccount().GetAddress(), destChainId, groupId, groupName) - txResp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msgMirrorGroup}, &txOption) + txResp, err := c.BroadcastTx(ctx, []sdk.Msg{msgMirrorGroup}, &txOption) if err != nil { return nil, err } @@ -124,7 +124,7 @@ func (c *client) MirrorGroup(ctx context.Context, destChainId sdk.ChainID, group // MirrorBucket mirrors the bucket to BSC as NFT func (c *client) MirrorBucket(ctx context.Context, destChainId sdk.ChainID, bucketId math.Uint, bucketName string, txOption gnfdSdkTypes.TxOption) (*sdk.TxResponse, error) { msgMirrorBucket := storagetypes.NewMsgMirrorBucket(c.MustGetDefaultAccount().GetAddress(), destChainId, bucketId, bucketName) - txResp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msgMirrorBucket}, &txOption) + txResp, err := c.BroadcastTx(ctx, []sdk.Msg{msgMirrorBucket}, &txOption) if err != nil { return nil, err } @@ -134,7 +134,7 @@ func (c *client) MirrorBucket(ctx context.Context, destChainId sdk.ChainID, buck // MirrorObject mirrors the object to BSC as NFT func (c *client) MirrorObject(ctx context.Context, destChainId sdk.ChainID, objectId math.Uint, bucketName, objectName string, txOption gnfdSdkTypes.TxOption) (*sdk.TxResponse, error) { msgMirrorObject := storagetypes.NewMsgMirrorObject(c.MustGetDefaultAccount().GetAddress(), destChainId, objectId, bucketName, objectName) - txResp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msgMirrorObject}, &txOption) + txResp, err := c.BroadcastTx(ctx, []sdk.Msg{msgMirrorObject}, &txOption) if err != nil { return nil, err } diff --git a/client/api_distribution.go b/client/api_distribution.go index 940fe74e..3b67959a 100644 --- a/client/api_distribution.go +++ b/client/api_distribution.go @@ -23,7 +23,7 @@ func (c *client) SetWithdrawAddress(ctx context.Context, withdrawAddr string, tx return "", err } msg := distrtypes.NewMsgSetWithdrawAddress(c.MustGetDefaultAccount().GetAddress(), withdraw) - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) if err != nil { return "", err } @@ -33,7 +33,7 @@ func (c *client) SetWithdrawAddress(ctx context.Context, withdrawAddr string, tx // WithdrawValidatorCommission withdraw accumulated commission by validator func (c *client) WithdrawValidatorCommission(ctx context.Context, txOption gnfdsdktypes.TxOption) (string, error) { msg := distrtypes.NewMsgWithdrawValidatorCommission(c.MustGetDefaultAccount().GetAddress()) - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) if err != nil { return "", err } @@ -47,7 +47,7 @@ func (c *client) WithdrawDelegatorReward(ctx context.Context, validatorAddr stri return "", err } msg := distrtypes.NewMsgWithdrawDelegatorReward(c.MustGetDefaultAccount().GetAddress(), validator) - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) if err != nil { return "", err } @@ -57,7 +57,7 @@ func (c *client) WithdrawDelegatorReward(ctx context.Context, validatorAddr stri // FundCommunityPool sends coins directly from the sender to the community pool. func (c *client) FundCommunityPool(ctx context.Context, amount math.Int, txOption gnfdsdktypes.TxOption) (string, error) { msg := distrtypes.NewMsgFundCommunityPool(sdk.Coins{sdk.Coin{Denom: gnfdsdktypes.Denom, Amount: amount}}, c.MustGetDefaultAccount().GetAddress()) - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) if err != nil { return "", err } diff --git a/client/api_feegrant.go b/client/api_feegrant.go index 4a24db5c..ed89ace4 100644 --- a/client/api_feegrant.go +++ b/client/api_feegrant.go @@ -37,7 +37,7 @@ func (c *client) GrantBasicAllowance(ctx context.Context, granteeAddr string, fe if err != nil { return "", err } - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) if err != nil { return "", err } @@ -54,7 +54,7 @@ func (c *client) GrantAllowance(ctx context.Context, granteeAddr string, allowan if err != nil { return "", err } - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) if err != nil { return "", err } @@ -71,7 +71,7 @@ func (c *client) RevokeAllowance(ctx context.Context, granteeAddr string, txOpti if err != nil { return "", err } - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{&msg}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{&msg}, &txOption) if err != nil { return "", err } diff --git a/client/api_object.go b/client/api_object.go index a65c0db2..797c667a 100644 --- a/client/api_object.go +++ b/client/api_object.go @@ -17,8 +17,6 @@ import ( "strings" "time" - ctypes "github.com/cometbft/cometbft/rpc/core/types" - hashlib "github.com/bnb-chain/greenfield-common/go/hash" "github.com/bnb-chain/greenfield-go-sdk/pkg/utils" "github.com/bnb-chain/greenfield-go-sdk/types" @@ -178,22 +176,21 @@ func (c *client) CreateObject(ctx context.Context, bucketName, objectName string opts.TxOpts = &gnfdsdk.TxOption{Mode: &broadcastMode} } - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{signedCreateObjectMsg}, opts.TxOpts) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{signedCreateObjectMsg}, opts.TxOpts) if err != nil { return "", err } txnHash := resp.TxResponse.TxHash - var txnResponse *ctypes.ResultTx if !opts.IsAsyncMode { ctxTimeout, cancel := context.WithTimeout(ctx, types.ContextTimeout) defer cancel() - txnResponse, err = c.WaitForTx(ctxTimeout, txnHash) + txnResponse, err := c.WaitForTx(ctxTimeout, txnHash) if err != nil { return txnHash, fmt.Errorf("the transaction has been submitted, please check it later:%v", err) } if txnResponse.TxResult.Code != 0 { - return txnHash, fmt.Errorf("the createObject txn has failed with response code: %d", txnResponse.TxResult.Code) + return txnHash, fmt.Errorf("the createObject txn has failed with response code: %d, codespace:%s", txnResponse.TxResult.Code, txnResponse.TxResult.Codespace) } } return txnHash, nil diff --git a/client/api_payment.go b/client/api_payment.go index 392f5829..4d43fec1 100644 --- a/client/api_payment.go +++ b/client/api_payment.go @@ -53,7 +53,7 @@ func (c *client) Deposit(ctx context.Context, toAddress string, amount math.Int, To: accAddress.String(), Amount: amount, } - tx, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msgDeposit}, &txOption) + tx, err := c.BroadcastTx(ctx, []sdk.Msg{msgDeposit}, &txOption) if err != nil { return "", err } @@ -71,7 +71,7 @@ func (c *client) Withdraw(ctx context.Context, fromAddress string, amount math.I From: accAddress.String(), Amount: amount, } - tx, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msgWithdraw}, &txOption) + tx, err := c.BroadcastTx(ctx, []sdk.Msg{msgWithdraw}, &txOption) if err != nil { return "", err } @@ -88,7 +88,7 @@ func (c *client) DisableRefund(ctx context.Context, paymentAddress string, txOpt Owner: c.MustGetDefaultAccount().GetAddress().String(), Addr: accAddress.String(), } - tx, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msgDisableRefund}, &txOption) + tx, err := c.BroadcastTx(ctx, []sdk.Msg{msgDisableRefund}, &txOption) if err != nil { return "", err } diff --git a/client/api_proposal.go b/client/api_proposal.go index f364a91e..87204d88 100644 --- a/client/api_proposal.go +++ b/client/api_proposal.go @@ -28,7 +28,7 @@ func (c *client) SubmitProposal(ctx context.Context, msgs []sdk.Msg, depositAmou if err != nil { return 0, "", err } - txResp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msgSubmitProposal}, &opts.TxOption) + txResp, err := c.BroadcastTx(ctx, []sdk.Msg{msgSubmitProposal}, &opts.TxOption) if err != nil { return 0, "", err } @@ -55,7 +55,7 @@ func (c *client) SubmitProposal(ctx context.Context, msgs []sdk.Msg, depositAmou func (c *client) VoteProposal(ctx context.Context, proposalID uint64, voteOption govTypesV1.VoteOption, opts types.VoteProposalOptions) (string, error) { msgVote := govTypesV1.NewMsgVote(c.MustGetDefaultAccount().GetAddress(), proposalID, voteOption, opts.Metadata) - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msgVote}, &opts.TxOption) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{msgVote}, &opts.TxOption) if err != nil { return "", err } diff --git a/client/api_sp.go b/client/api_sp.go index 89bc15f3..144590ab 100644 --- a/client/api_sp.go +++ b/client/api_sp.go @@ -222,7 +222,7 @@ func (c *client) GrantDepositForStorageProvider(ctx context.Context, spAddr stri if err != nil { return "", err } - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msgGrant}, &opts.TxOption) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{msgGrant}, &opts.TxOption) if err != nil { return "", err } @@ -240,7 +240,7 @@ func (c *client) UpdateSpStoragePrice(ctx context.Context, spAddr string, readPr StorePrice: storePrice, FreeReadQuota: freeReadQuota, } - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msgUpdateStoragePrice}, &TxOption) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{msgUpdateStoragePrice}, &TxOption) if err != nil { return "", err } @@ -257,7 +257,7 @@ func (c *client) UpdateSpStatus(ctx context.Context, spAddr string, status spTyp Status: status, Duration: duration, } - resp, err := c.chainClient.BroadcastTx(ctx, []sdk.Msg{msgUpdateSpStatus}, &TxOption) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{msgUpdateSpStatus}, &TxOption) if err != nil { return "", err } diff --git a/client/api_validator.go b/client/api_validator.go index 970907a3..223cf808 100644 --- a/client/api_validator.go +++ b/client/api_validator.go @@ -98,7 +98,7 @@ func (c *client) EditValidator(ctx context.Context, description stakingtypes.Des return "", err } msg := stakingtypes.NewMsgEditValidator(c.MustGetDefaultAccount().GetAddress(), description, newRate, newMinSelfDelegation, relayer, challenger, newBlsKey, blsProof) - resp, err := c.chainClient.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) if err != nil { return "", err } @@ -112,7 +112,7 @@ func (c *client) DelegateValidator(ctx context.Context, validatorAddr string, am return "", err } msg := stakingtypes.NewMsgDelegate(c.MustGetDefaultAccount().GetAddress(), validator, sdktypes.NewCoin(gnfdsdktypes.Denom, amount)) - resp, err := c.chainClient.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) if err != nil { return "", err } @@ -130,7 +130,7 @@ func (c *client) BeginRedelegate(ctx context.Context, validatorSrcAddr, validato return "", err } msg := stakingtypes.NewMsgBeginRedelegate(c.MustGetDefaultAccount().GetAddress(), validatorSrc, validatorDest, sdktypes.NewCoin(gnfdsdktypes.Denom, amount)) - resp, err := c.chainClient.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) if err != nil { return "", err } @@ -144,7 +144,7 @@ func (c *client) Undelegate(ctx context.Context, validatorAddr string, amount ma return "", err } msg := stakingtypes.NewMsgUndelegate(c.MustGetDefaultAccount().GetAddress(), validator, sdktypes.NewCoin(gnfdsdktypes.Denom, amount)) - resp, err := c.chainClient.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) if err != nil { return "", err } @@ -158,7 +158,7 @@ func (c *client) CancelUnbondingDelegation(ctx context.Context, validatorAddr st return "", err } msg := stakingtypes.NewMsgCancelUnbondingDelegation(c.MustGetDefaultAccount().GetAddress(), validator, creationHeight, sdktypes.NewCoin(gnfdsdktypes.Denom, amount)) - resp, err := c.chainClient.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) if err != nil { return "", err } @@ -186,7 +186,7 @@ func (c *client) GrantDelegationForValidator(ctx context.Context, delegationAmou return "", err } - resp, err := c.chainClient.BroadcastTx(ctx, []sdktypes.Msg{msgGrant}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdktypes.Msg{msgGrant}, &txOption) if err != nil { return "", err } @@ -196,7 +196,7 @@ func (c *client) GrantDelegationForValidator(ctx context.Context, delegationAmou // UnJailValidator unjails the validator func (c *client) UnJailValidator(ctx context.Context, txOption gnfdsdktypes.TxOption) (string, error) { msg := slashingtypes.NewMsgUnjail(c.MustGetDefaultAccount().GetAddress()) - resp, err := c.chainClient.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) if err != nil { return "", err } @@ -210,7 +210,7 @@ func (c *client) ImpeachValidator(ctx context.Context, validatorAddr string, txO return "", err } msg := slashingtypes.NewMsgImpeach(validator, c.MustGetDefaultAccount().GetAddress()) - resp, err := c.chainClient.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) + resp, err := c.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) if err != nil { return "", err } From ea47ed185dbab0847386766c03bf059d92a7c13e Mon Sep 17 00:00:00 2001 From: Alexxxxxx <118710506+alexgao001@users.noreply.github.com> Date: Mon, 18 Sep 2023 10:35:31 +0800 Subject: [PATCH 2/8] test: add e2e for tampering object (#181) * add e2e for tampering object * reduce object size small * extend the waiting period for sealing object * change SP tag --- .github/workflows/e2e.yml | 2 +- client/api_object.go | 1 - e2e/e2e_storage_test.go | 55 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 5a1af988..b34217d0 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -13,7 +13,7 @@ on: env: GreenfieldTag: v0.2.5 - GreenfieldStorageProviderTag: v0.2.5-alpha.3 + GreenfieldStorageProviderTag: develop GOPRIVATE: github.com/bnb-chain GH_ACCESS_TOKEN: ${{ secrets.GH_TOKEN }} MYSQL_USER: root diff --git a/client/api_object.go b/client/api_object.go index 797c667a..5682504b 100644 --- a/client/api_object.go +++ b/client/api_object.go @@ -232,7 +232,6 @@ func (c *client) PutObject(ctx context.Context, bucketName, objectName string, o if objectSize <= 0 { return errors.New("object size should be more than 0") } - params, err := c.GetParams() if err != nil { return err diff --git a/e2e/e2e_storage_test.go b/e2e/e2e_storage_test.go index 1e8614d1..21e932a5 100644 --- a/e2e/e2e_storage_test.go +++ b/e2e/e2e_storage_test.go @@ -564,3 +564,58 @@ func (s *StorageTestSuite) Test_Resumable_Upload_And_Download() { s.Require().True(isSame) s.Require().NoError(err) } + +func (s *StorageTestSuite) Test_Upload_Object_With_Tampering_Content() { + bucketName := storageTestUtil.GenRandomBucketName() + objectName := storageTestUtil.GenRandomObjectName() + + s.T().Logf("BucketName:%s, objectName: %s", bucketName, objectName) + + bucketTx, err := s.Client.CreateBucket(s.ClientContext, bucketName, s.PrimarySP.OperatorAddress, types.CreateBucketOptions{}) + s.Require().NoError(err) + + _, err = s.Client.WaitForTx(s.ClientContext, bucketTx) + s.Require().NoError(err) + + bucketInfo, err := s.Client.HeadBucket(s.ClientContext, bucketName) + s.Require().NoError(err) + if err == nil { + s.Require().Equal(bucketInfo.Visibility, storageTypes.VISIBILITY_TYPE_PRIVATE) + } + var buffer bytes.Buffer + line := `1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,123456789012` + for i := 0; i < 1024; i++ { + buffer.WriteString(fmt.Sprintf("[%05d] %s\n", i, line)) + } + var tamperingBuffer bytes.Buffer + tamperingLine := `0987654321,0987654321,0987654321,0987654321,0987654321,0987654321,0987654321,0987654321,098765432112` + for i := 0; i < 1024; i++ { + tamperingBuffer.WriteString(fmt.Sprintf("[%05d] %s\n", i, tamperingLine)) + } + + s.T().Log("---> CreateObject and HeadObject <---") + objectTx, err := s.Client.CreateObject(s.ClientContext, bucketName, objectName, bytes.NewReader(buffer.Bytes()), types.CreateObjectOptions{}) + s.Require().NoError(err) + _, err = s.Client.WaitForTx(s.ClientContext, objectTx) + s.Require().NoError(err) + + time.Sleep(5 * time.Second) + objectDetail, err := s.Client.HeadObject(s.ClientContext, bucketName, objectName) + s.Require().NoError(err) + s.Require().Equal(objectDetail.ObjectInfo.ObjectName, objectName) + s.Require().Equal(objectDetail.ObjectInfo.GetObjectStatus().String(), "OBJECT_STATUS_CREATED") + + objectSize := int64(tamperingBuffer.Len()) + s.T().Logf("---> PutObject and GetObject, objectName:%s objectSize:%d <---", objectName, objectSize) + err = s.Client.PutObject(s.ClientContext, bucketName, objectName, objectSize, + bytes.NewReader(tamperingBuffer.Bytes()), types.PutObjectOptions{}) + s.Require().Error(err) + + time.Sleep(20 * time.Second) + + // Object should not be sealed + objectDetail, err = s.Client.HeadObject(s.ClientContext, bucketName, objectName) + s.Require().NoError(err) + s.Require().Equal(objectDetail.ObjectInfo.ObjectName, objectName) + s.Require().Equal(objectDetail.ObjectInfo.GetObjectStatus().String(), "OBJECT_STATUS_CREATED") +} From 1642005898c9d892e0c749738029250f48f894cf Mon Sep 17 00:00:00 2001 From: Alexxxxxx <118710506+alexgao001@users.noreply.github.com> Date: Wed, 20 Sep 2023 18:09:03 +0800 Subject: [PATCH 3/8] fix: fix impeach validator api (#188) * fix impeach api * fix e2e key path --- client/api_validator.go | 15 ++++++++------- e2e/e2e_validator_test.go | 26 +++++++++++++++++++------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/client/api_validator.go b/client/api_validator.go index 223cf808..1b323d39 100644 --- a/client/api_validator.go +++ b/client/api_validator.go @@ -37,7 +37,7 @@ type Validator interface { GrantDelegationForValidator(ctx context.Context, delegationAmount math.Int, txOption gnfdsdktypes.TxOption) (string, error) UnJailValidator(ctx context.Context, txOption gnfdsdktypes.TxOption) (string, error) - ImpeachValidator(ctx context.Context, validatorAddr string, txOption gnfdsdktypes.TxOption) (string, error) + ImpeachValidator(ctx context.Context, validatorAddr string, proposalDepositAmount math.Int, proposalTitle, proposalSummary, proposalMetadata string, txOption gnfdsdktypes.TxOption) (uint64, string, error) } func (c *client) ListValidators(ctx context.Context, status string) (*stakingtypes.QueryValidatorsResponse, error) { @@ -204,17 +204,18 @@ func (c *client) UnJailValidator(ctx context.Context, txOption gnfdsdktypes.TxOp } // ImpeachValidator impeaches a validator -func (c *client) ImpeachValidator(ctx context.Context, validatorAddr string, txOption gnfdsdktypes.TxOption) (string, error) { +func (c *client) ImpeachValidator(ctx context.Context, validatorAddr string, proposalDepositAmount math.Int, proposalTitle, proposalSummary, proposalMetadata string, txOption gnfdsdktypes.TxOption) (uint64, string, error) { validator, err := sdktypes.AccAddressFromHexUnsafe(validatorAddr) if err != nil { - return "", err + return 0, "", err } - msg := slashingtypes.NewMsgImpeach(validator, c.MustGetDefaultAccount().GetAddress()) - resp, err := c.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) + govModule, err := c.GetModuleAccountByName(ctx, govTypes.ModuleName) if err != nil { - return "", err + return 0, "", err } - return resp.TxResponse.TxHash, nil + govAccountAddr := govModule.GetAddress() + msg := slashingtypes.NewMsgImpeach(validator, govAccountAddr) + return c.SubmitProposal(ctx, []sdktypes.Msg{msg}, proposalDepositAmount, proposalTitle, proposalSummary, types.SubmitProposalOptions{Metadata: proposalMetadata, TxOption: txOption}) } func pubKeyFromHex(pk string) (cryptotypes.PubKey, error) { diff --git a/e2e/e2e_validator_test.go b/e2e/e2e_validator_test.go index 2684e7d1..7f5b2128 100644 --- a/e2e/e2e_validator_test.go +++ b/e2e/e2e_validator_test.go @@ -151,13 +151,25 @@ func (s *ValidatorTestSuite) Test_Validator_Operations() { // query the new validator, status is BONDED again validators, err = s.Client.ListValidators(context.Background(), "BOND_STATUS_BONDED") s.Require().NoError(err) - isPresent = false - for _, v := range validators.Validators { - if v.SelfDelAddress == newValidatorAddr.String() { - isPresent = true - } - } - s.Require().True(isPresent) + s.Require().Equal(len(validators.Validators), 2) + + // create a proposal to impeach the new Validator + s.Client.SetDefaultAccount(validator0Account) + proposalID, txHash, err = s.Client.ImpeachValidator(context.Background(), newValidatorAddr.String(), delegationAmount, "title", "summary ", "meta", gnfdsdktypes.TxOption{}) + s.Require().NoError(err) + _, err = s.Client.WaitForTx(s.ClientContext, txHash) + s.Require().NoError(err) + + // vote for the proposal + txHash, err = s.Client.VoteProposal(s.ClientContext, proposalID, govTypesV1.OptionYes, types.VoteProposalOptions{}) + s.Require().NoError(err) + _, err = s.Client.WaitForTx(s.ClientContext, txHash) + s.Require().NoError(err) + err = s.Client.WaitForNBlocks(s.ClientContext, 10) + s.Require().NoError(err) + validators, err = s.Client.ListValidators(context.Background(), "BOND_STATUS_BONDED") + s.Require().NoError(err) + s.Require().Equal(len(validators.Validators), 1) } func TestValidatorTestSuite(t *testing.T) { From 236d44c89c248f34fb6311edfe8f6319e9ccfccb Mon Sep 17 00:00:00 2001 From: Barry <122767193+BarryTong65@users.noreply.github.com> Date: Thu, 21 Sep 2023 16:37:55 +0800 Subject: [PATCH 4/8] feat: list groups by ids (#191) * docs: impl list groups by ids and update list user payments * fix: lower case type and comments --- client/api_group.go | 105 ++++++++++++++++++++++++++++++++++++++++++++ examples/group.go | 13 ++++++ examples/payment.go | 6 +-- types/list.go | 30 ++++++++++--- 4 files changed, 146 insertions(+), 8 deletions(-) diff --git a/client/api_group.go b/client/api_group.go index e916c28d..06ec7c82 100644 --- a/client/api_group.go +++ b/client/api_group.go @@ -74,6 +74,7 @@ type Group interface { // ListGroupsByOwner returns a list of groups owned by the specified user, including those for which the user's expiration time has already elapsed // By default, the user is the sender. Other users can be set using the option ListGroupsByOwner(ctx context.Context, opts types.GroupsOwnerPaginationOptions) (*types.GroupsResult, error) + ListGroupsByGroupID(ctx context.Context, groupIDs []uint64, opts types.EndPointOptions) (types.ListGroupsByGroupIDResponse, error) } // CreateGroup create a new group on greenfield chain, the group members can be initialized or not @@ -568,3 +569,107 @@ func (c *client) ListGroupsByOwner(ctx context.Context, opts types.GroupsOwnerPa return groups, nil } + +type gfSpListGroupsByGroupIDsResponse map[uint64]*types.GroupMeta + +type groupEntry struct { + Id uint64 + Value *types.GroupMeta +} + +// UnmarshalXML unmarshal gfSpListGroupsByGroupIDsResponse xml response type +func (m *gfSpListGroupsByGroupIDsResponse) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *m = gfSpListGroupsByGroupIDsResponse{} + for { + var e groupEntry + + err := d.Decode(&e) + if err == io.EOF { + break + } else if err != nil { + return err + } else { + (*m)[e.Id] = e.Value + } + } + return nil +} + +// ListGroupsByGroupID - List groups by group ids. +// +// By inputting a collection of group IDs, we can retrieve the corresponding object data. If the group is nonexistent or has been deleted, a null value will be returned +// +// - ctx: Context variables for the current API call. +// +// - groupIDs: The list of group ids. +// +// - opts: The options to set the meta to list groups by group id. +// +// - ret1: The result of group info map by given group ids. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *client) ListGroupsByGroupID(ctx context.Context, groupIDs []uint64, opts types.EndPointOptions) (types.ListGroupsByGroupIDResponse, error) { + const MaximumListBucketsSize = 1000 + if len(groupIDs) == 0 || len(groupIDs) > MaximumListBucketsSize { + return types.ListGroupsByGroupIDResponse{}, nil + } + + groupIDMap := make(map[uint64]bool) + for _, id := range groupIDs { + if _, ok := groupIDMap[id]; ok { + // repeat id keys in request + return types.ListGroupsByGroupIDResponse{}, nil + } + groupIDMap[id] = true + } + + idStr := make([]string, len(groupIDs)) + for i, id := range groupIDs { + idStr[i] = strconv.FormatUint(id, 10) + } + IDs := strings.Join(idStr, ",") + + params := url.Values{} + params.Set("groups-query", "") + params.Set("ids", IDs) + + reqMeta := requestMeta{ + urlValues: params, + contentSHA256: types.EmptyStringSHA256, + } + + sendOpt := sendOptions{ + method: http.MethodGet, + disableCloseBody: true, + } + + endpoint, err := c.getEndpointByOpt(&opts) + if err != nil { + log.Error().Msg(fmt.Sprintf("get endpoint by option failed %s", err.Error())) + return types.ListGroupsByGroupIDResponse{}, err + + } + + resp, err := c.sendReq(ctx, reqMeta, &sendOpt, endpoint) + if err != nil { + return types.ListGroupsByGroupIDResponse{}, err + } + defer utils.CloseResponse(resp) + + buf := new(strings.Builder) + _, err = io.Copy(buf, resp.Body) + if err != nil { + log.Error().Msgf("the list of groups in group ids:%v failed: %s", groupIDs, err.Error()) + return types.ListGroupsByGroupIDResponse{}, err + } + + groups := types.ListGroupsByGroupIDResponse{} + bufStr := buf.String() + err = xml.Unmarshal([]byte(bufStr), (*gfSpListGroupsByGroupIDsResponse)(&groups.Groups)) + if err != nil && groups.Groups == nil { + log.Error().Msgf("the list of groups in group ids:%v failed: %s", groups, err.Error()) + return types.ListGroupsByGroupIDResponse{}, err + } + + return groups, nil +} diff --git a/examples/group.go b/examples/group.go index b4be4691..5c20044f 100644 --- a/examples/group.go +++ b/examples/group.go @@ -104,6 +104,19 @@ func main() { log.Printf("name: %s, source type: %s\n", group.Group.GroupName, group.Group.SourceType) } + ids := []uint64{1, 2, 333} + // list groups by group ids + groupList, err := cli.ListGroupsByGroupID(ctx, ids, types.EndPointOptions{ + Endpoint: httpsAddr, + SPAddress: "", + }) + log.Println("list groups result:") + for _, group := range groupList.Groups { + if group != nil { + log.Printf("name: %s, source type: %s\n", group.Group.GroupName, group.Group.SourceType) + } + } + // delete group delTx, err := cli.DeleteGroup(ctx, groupName, types.DeleteGroupOption{}) handleErr(err, "DeleteGroup") diff --git a/examples/payment.go b/examples/payment.go index 6c30b044..a3b80521 100644 --- a/examples/payment.go +++ b/examples/payment.go @@ -57,11 +57,11 @@ func main() { handleErr(err, "GetStreamRecord") log.Printf("stream record has balance %s", streamRecordAfterWithdraw.StaticBalance) streamRecords, err := cli.ListUserPaymentAccounts(ctx, types.ListUserPaymentAccountsOptions{ - Account: "0x4FEAA841B3436624C54B652695320830FCB1B309", + Account: "0x6bda8d05a24688f1f2ed05e503d19576aba7da2c", Endpoint: httpsAddr, SPAddress: "", }) - for _, record := range streamRecords.StreamRecords { - log.Printf("stream record %s", record.StreamRecord.OutFlowCount) + for _, record := range streamRecords.PaymentAccounts { + log.Printf("payment account %s", record.PaymentAccount.Address) } } diff --git a/types/list.go b/types/list.go index 0234a4fc..8c1d53a6 100644 --- a/types/list.go +++ b/types/list.go @@ -75,8 +75,8 @@ type ListBucketsByPaymentAccountResult struct { } type ListUserPaymentAccountsResult struct { - // StreamRecords defines the list of stream records - StreamRecords []*StreamRecordsMeta `xml:"StreamRecords"` + // PaymentAccount defines the list of payment accounts + PaymentAccounts []*PaymentAccounts `xml:"PaymentAccounts"` } type ListGroupsResult struct { @@ -274,6 +274,12 @@ type ListBucketsByBucketIDResponse struct { Buckets map[uint64]*BucketMeta `xml:"Buckets"` } +// ListGroupsByGroupIDResponse is response type for the ListGroupsByGroupID +type ListGroupsByGroupIDResponse struct { + // Groups defines the information of a group map + Groups map[uint64]*GroupMeta `xml:"Groups"` +} + // GroupMeta is the structure for group information type GroupMeta struct { // group defines the basic group info @@ -308,11 +314,11 @@ type GroupInfo struct { Extra string `xml:"Extra"` } -type StreamRecordsMeta struct { +type PaymentAccounts struct { + // refundable defines the payment account is refundable or not + PaymentAccount *PaymentAccount `xml:"PaymentAccount"` // stream_records defines stream payment records of a stream account StreamRecord *StreamRecord `xml:"StreamRecord"` - // refundable defines the payment account is refundable or not - Refundable bool `xml:"Refundable"` } // StreamRecord defines Record of a stream account @@ -341,6 +347,20 @@ type StreamRecord struct { FrozenNetflowRate int64 `xml:"FrozenNetflowRate"` } +// PaymentAccount defines payment account info +type PaymentAccount struct { + // Address defines the address of payment account + Address string `xml:"Address"` + // Owner defines the owner of this payment account + Owner string `xml:"Owner"` + // Refundable defines the payment account is refundable or not + Refundable bool `xml:"Refundable"` + // UpdateAt defines the update block height of this payment account + UpdateAt int64 `xml:"UpdateAt"` + // UpdateTime defines the update time of this payment account + UpdateTime int64 `xml:"UpdateTime"` +} + type ListObjectPoliciesResponse struct { Policies []*PolicyMeta `xml:"Policies"` } From e6b5db6bf98e6b9b6a7a20be39d6342381a9ccd4 Mon Sep 17 00:00:00 2001 From: KeefeL <90749943+KeefeL@users.noreply.github.com> Date: Thu, 21 Sep 2023 18:17:59 +0800 Subject: [PATCH 5/8] docs: refactor for adding comments (#180) * docs: refactor for adding comments * docs: refine Basic, Group, SP, VG Clients and types.go documentation. (#184) * doc: refactor for adding comments * Refine Basic, Group, SP, VG, and types.go documentation. * fix format * enrich comments --------- Co-authored-by: Keefe Liu * docs: refine the go doc of the cross-chain related apis (#187) * docs: refine the go doc of the cross-chain related apis * fix comment * docs: refine the go doc of payment apis (#185) * doc: refine the go doc of payment apis * doc: refine the go doc of payment apis * fix review comments * docs: refine the go doc of validator/staking apis (#186) * docs: refine the go doc of validator/staking apis * fix review comments * fix: fix bucket and object API doc (#189) * docs: refine the comments of bucket api * docs: update metadata list apis and option.go * doc: improve the comments of bucket api * fix: fix the object api comments * fix: fix the object interface --------- Co-authored-by: BarryTong65 * fix: go-sdk doc for off chain auth (#190) * fix: go-sdk doc for off chain auth * fix: go-sdk doc for off chain auth - adding input description. --------- Co-authored-by: Clyde * docs: refine the go doc of challenge apis (#183) * doc: refine the go doc of challenge apis * doc: refine the go doc of challenge apis * fix review comments --------- Co-authored-by: Keefe Liu * fix: fix e2e (#192) * docs: add comments for the account file * fix: fix list.go comment (#194) * fix: fix list.go comment (#197) * fix: fix group api (#198) --------- Co-authored-by: Keefe Liu Co-authored-by: Alexxxxxx <118710506+alexgao001@users.noreply.github.com> Co-authored-by: yutianwu Co-authored-by: forcodedancing Co-authored-by: flywukong <2229306838@qq.com> Co-authored-by: BarryTong65 Co-authored-by: ruojunm <46366167+ruojunm@users.noreply.github.com> Co-authored-by: Clyde Co-authored-by: Barry <122767193+BarryTong65@users.noreply.github.com> --- client/api_account.go | 176 +++++++++++++--- client/api_basic.go | 266 +++++++++++++++++++----- client/api_bucket.go | 365 ++++++++++++++++++++++++++------- client/api_challenge.go | 127 ++++++++++-- client/api_client.go | 157 ++++++-------- client/api_crosschain.go | 157 ++++++++++++-- client/api_distribution.go | 56 ++++- client/api_feegrant.go | 16 +- client/api_group.go | 294 +++++++++++++++++++------- client/api_object.go | 170 ++++++++------- client/api_off_chain_auth.go | 91 +++++--- client/api_payment.go | 81 ++++++-- client/api_proposal.go | 53 ++++- client/api_sp.go | 155 +++++++++++--- client/api_validator.go | 214 ++++++++++++++++--- client/api_virtual_group.go | 17 +- client/doc.go | 2 +- e2e/basesuite/suite.go | 4 +- e2e/e2e_migrate_bucket_test.go | 9 +- examples/common.go | 2 +- examples/crosschain.go | 4 +- examples/crosschain_gov.go | 2 +- types/account.go | 45 +++- types/const.go | 2 +- types/list.go | 285 +++++++++++++------------ types/option.go | 278 +++++++++++++------------ types/types.go | 22 +- 27 files changed, 2190 insertions(+), 860 deletions(-) diff --git a/client/api_account.go b/client/api_account.go index 2417672b..31aaac26 100644 --- a/client/api_account.go +++ b/client/api_account.go @@ -12,7 +12,12 @@ import ( bankTypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) -type Account interface { +// IAccountClient - Client APIs for operating Greenfield accounts. +type IAccountClient interface { + SetDefaultAccount(account *types.Account) + GetDefaultAccount() (*types.Account, error) + MustGetDefaultAccount() *types.Account + GetAccount(ctx context.Context, address string) (authTypes.AccountI, error) GetAccountBalance(ctx context.Context, address string) (*sdk.Coin, error) GetPaymentAccount(ctx context.Context, address string) (*paymentTypes.PaymentAccount, error) @@ -25,14 +30,54 @@ type Account interface { MultiTransfer(ctx context.Context, details []types.TransferDetail, txOption gnfdSdkTypes.TxOption) (string, error) } -// GetAccount retrieves account information for a given address. -// It takes a context and an address as input and returns an AccountI interface and an error (if any). -func (c *client) GetAccount(ctx context.Context, address string) (authTypes.AccountI, error) { +// SetDefaultAccount - Set the default account of the Client. +// +// If you call other APIs without specifying the account, it will be assumed that you are operating on the default +// account. This includes sending transactions and other actions. +// +// - account: The account to be set as the default account, should be created using a private key or a mnemonic phrase. +func (c *Client) SetDefaultAccount(account *types.Account) { + c.defaultAccount = account + c.chainClient.SetKeyManager(account.GetKeyManager()) +} + +// GetDefaultAccount - Get the default account of the Client. +// +// - ret1: The default account of the Client. +// +// - ret2: Return error when default account doesn't exist, otherwise return nil. +func (c *Client) GetDefaultAccount() (*types.Account, error) { + if c.defaultAccount == nil { + return nil, types.ErrorDefaultAccountNotExist + } + return c.defaultAccount, nil +} + +// MustGetDefaultAccount - Get the default account of the Client, panic when account not found. +// +// - ret1: The default account of the Client. +func (c *Client) MustGetDefaultAccount() *types.Account { + if c.defaultAccount == nil { + panic("Default account not exist, Use SetDefaultAccount to set ") + } + return c.defaultAccount +} + +// GetAccount - Retrieve on-chain account information for a given address. +// +// - ctx: Context variables for the current API call. +// +// - address: The given address for retrieving. +// +// - ret1: The account interface for the given address. +// +// - ret2: Return error when getting account failed, otherwise return nil. +func (c *Client) GetAccount(ctx context.Context, address string) (authTypes.AccountI, error) { accAddress, err := sdk.AccAddressFromHexUnsafe(address) if err != nil { return nil, err } - // Call the DefaultAccount method of the chain client with a QueryAccountRequest containing the address. + // Call the DefaultAccount method of the chain Client with a QueryAccountRequest containing the address. response, err := c.chainClient.Account(ctx, &authTypes.QueryAccountRequest{Address: accAddress.String()}) if err != nil { // Return an error if there was an issue retrieving the account. @@ -51,9 +96,23 @@ func (c *client) GetAccount(ctx context.Context, address string) (authTypes.Acco return &baseAccount, err } -// CreatePaymentAccount creates a new payment account on the blockchain using the provided address. -// It returns a TxResponse containing information about the transaction, or an error if the transaction failed. -func (c *client) CreatePaymentAccount(ctx context.Context, address string, txOption gnfdSdkTypes.TxOption) (string, error) { +// CreatePaymentAccount - Create a new payment account for the given address. +// +// The payment account is used to pay for the storage and read quota fee of objects. When you need to pay for different +// buckets separately, you can create different payment accounts to do so. Note that the payment account does not have a +// private key, and only the owner of the payment account can withdraw funds from it. Once the owner revokes permission +// for withdrawal, the funds in the payment account can only be utilized to cover storage and read quota fees. +// +// - ctx: Context variables for the current API call. +// +// - address: The owner address of the new payment account. +// +// - txOption: The txOption for sending transactions. +// +// - ret1: Return the transaction hash if created successfully, otherwise return empty string. +// +// - ret2: Return error when created failed, otherwise return nil. +func (c *Client) CreatePaymentAccount(ctx context.Context, address string, txOption gnfdSdkTypes.TxOption) (string, error) { accAddress, err := sdk.AccAddressFromHexUnsafe(address) if err != nil { return "", err @@ -66,7 +125,16 @@ func (c *client) CreatePaymentAccount(ctx context.Context, address string, txOpt return tx.TxResponse.TxHash, nil } -func (c *client) GetModuleAccountByName(ctx context.Context, name string) (authTypes.ModuleAccountI, error) { +// GetModuleAccountByName - Get module account by module name. +// +// - ctx: Context variables for the current API call. +// +// - name: Module name. +// +// - ret1: The account interface for the given module name. +// +// - ret2: Return error when getting failed, otherwise return nil. +func (c *Client) GetModuleAccountByName(ctx context.Context, name string) (authTypes.ModuleAccountI, error) { response, err := c.chainClient.ModuleAccountByName(ctx, &authTypes.QueryModuleAccountByNameRequest{Name: name}) if err != nil { return nil, err @@ -83,7 +151,14 @@ func (c *client) GetModuleAccountByName(ctx context.Context, name string) (authT return &moduleAccount, err } -func (c *client) GetModuleAccounts(ctx context.Context) ([]authTypes.ModuleAccountI, error) { +// GetModuleAccounts - Get all module accounts. +// +// - ctx: Context variables for the current API call. +// +// - ret1: The account interface lists for all the module accounts. +// +// - ret2: Return error when getting failed, otherwise return nil. +func (c *Client) GetModuleAccounts(ctx context.Context) ([]authTypes.ModuleAccountI, error) { response, err := c.chainClient.ModuleAccounts(ctx, &authTypes.QueryModuleAccountsRequest{}) if err != nil { return nil, err @@ -101,9 +176,16 @@ func (c *client) GetModuleAccounts(ctx context.Context) ([]authTypes.ModuleAccou return accounts, err } -// GetAccountBalance retrieves balance information of an account for a given address. -// It takes a context and an address as input and returns an sdk.Coin interface and an error (if any). -func (c *client) GetAccountBalance(ctx context.Context, address string) (*sdk.Coin, error) { +// GetAccountBalance - Get the bank balance for the given address. +// +// - ctx: Context variables for the current API call. +// +// - address: The given address for retrieving. +// +// - ret1: The balance info for the given address, in sdk.Coin format. +// +// - ret2: Return error when getting failed, otherwise return nil. +func (c *Client) GetAccountBalance(ctx context.Context, address string) (*sdk.Coin, error) { accAddress, err := sdk.AccAddressFromHexUnsafe(address) if err != nil { return nil, err @@ -116,10 +198,16 @@ func (c *client) GetAccountBalance(ctx context.Context, address string) (*sdk.Co return response.Balance, nil } -// GetPaymentAccount function takes a context and an address string as parameters and returns a pointer to a paymentTypes.PaymentAccount struct and an error. -// This function uses the PaymentAccount method of the chainClient field of the client struct to query the payment account associated with the given address. -// If there is an error, the function returns nil and the error. If there is no error, the function returns a pointer to the PaymentAccount struct and nil. -func (c *client) GetPaymentAccount(ctx context.Context, address string) (*paymentTypes.PaymentAccount, error) { +// GetPaymentAccount - Get payment account by the payment account's address. +// +// - ctx: Context variables for the current API call. +// +// - address: The given payment account address for retrieving. +// +// - ret1: The payment account info for the given address. +// +// - ret2: Return error when getting failed, otherwise return nil. +func (c *Client) GetPaymentAccount(ctx context.Context, address string) (*paymentTypes.PaymentAccount, error) { accAddress, err := sdk.AccAddressFromHexUnsafe(address) if err != nil { return nil, err @@ -131,14 +219,21 @@ func (c *client) GetPaymentAccount(ctx context.Context, address string) (*paymen return &pa.PaymentAccount, nil } -// GetPaymentAccountsByOwner retrieves all payment accounts owned by the given address -// and returns a slice of PaymentAccount pointers and an error (if any). -func (c *client) GetPaymentAccountsByOwner(ctx context.Context, owner string) ([]*paymentTypes.PaymentAccount, error) { +// GetPaymentAccountsByOwner - Get all payment accounts owned by the given owner address. +// +// - ctx: Context variables for the current API call. +// +// - address: The given owner account address for retrieving. +// +// - ret1: The payment accounts list for the given owner address. +// +// - ret2: Return error when getting failed, otherwise return nil. +func (c *Client) GetPaymentAccountsByOwner(ctx context.Context, owner string) ([]*paymentTypes.PaymentAccount, error) { ownerAcc, err := sdk.AccAddressFromHexUnsafe(owner) if err != nil { return nil, err } - // Call the GetPaymentAccountsByOwner method of the chain client with a QueryGetPaymentAccountsByOwnerRequest containing the owner address. + // Call the GetPaymentAccountsByOwner method of the chain Client with a QueryGetPaymentAccountsByOwnerRequest containing the owner address. accountsByOwnerResponse, err := c.chainClient.PaymentAccountsByOwner(ctx, &paymentTypes.QueryPaymentAccountsByOwnerRequest{Owner: ownerAcc.String()}) if err != nil { return nil, err @@ -149,7 +244,7 @@ func (c *client) GetPaymentAccountsByOwner(ctx context.Context, owner string) ([ // Iterate over each account address returned in the response. for _, accAddress := range accountsByOwnerResponse.PaymentAccounts { - // Call the GetPaymentAccount method of the client to retrieve the PaymentAccount object for the given address. + // Call the GetPaymentAccount method of the Client to retrieve the PaymentAccount object for the given address. pa, err := c.GetPaymentAccount(ctx, accAddress) if err != nil { return nil, err @@ -162,15 +257,20 @@ func (c *client) GetPaymentAccountsByOwner(ctx context.Context, owner string) ([ return paymentAccounts, nil } -// Transfer function takes a context, a toAddress string, an amount of type math.Int, and a txOption of -// type gnfdSdkTypes.TxOption as parameters and returns a pointer to an sdk.TxResponse struct and an error. -// This function first parses the toAddress parameter into an sdk.AccAddress object, and if there is an error, -// it returns nil and the error. -// Then it generates a MsgSend message using the NewMsgSend method of the types3 package and broadcasts the -// transaction to the chain by calling the BroadcastTx method of the chainClient field of the client struct. -// If there is an error during the broadcasting, the function returns nil and the error. If there is no error, -// the function returns a pointer to the TxResponse struct and nil -func (c *client) Transfer(ctx context.Context, toAddress string, amount math.Int, txOption gnfdSdkTypes.TxOption) (string, error) { +// Transfer - Transfer BNB from sender to receiver. +// +// - ctx: Context variables for the current API call. +// +// - toAddress: The address who will receive the BNB. +// +// - amount: The BNB amount to transfer, 1e18 denotes 1BNB. +// +// - txOption: The txOption for sending transactions. +// +// - ret1: Return the transaction hash if transferred successfully, otherwise return empty string. +// +// - ret2: Return error if transferred failed, otherwise return nil. +func (c *Client) Transfer(ctx context.Context, toAddress string, amount math.Int, txOption gnfdSdkTypes.TxOption) (string, error) { toAddr, err := sdk.AccAddressFromHexUnsafe(toAddress) if err != nil { return "", err @@ -183,8 +283,18 @@ func (c *client) Transfer(ctx context.Context, toAddress string, amount math.Int return tx.TxResponse.TxHash, nil } -// MultiTransfer makes transfers from an account to multiple accounts with respect amounts -func (c *client) MultiTransfer(ctx context.Context, details []types.TransferDetail, txOption gnfdSdkTypes.TxOption) (string, error) { +// MultiTransfer - Transfer BNB from sender to multiple receivers. +// +// - ctx: Context variables for the current API call. +// +// - details: The receiver address and transfer amount list. +// +// - txOption: The txOption for sending transactions. +// +// - ret1: Return the transaction hash if transferred successfully, otherwise return empty string. +// +// - ret2: Return error if transferred failed, otherwise return nil. +func (c *Client) MultiTransfer(ctx context.Context, details []types.TransferDetail, txOption gnfdSdkTypes.TxOption) (string, error) { outputs := make([]bankTypes.Output, 0) denom := gnfdSdkTypes.Denom sum := math.NewInt(0) diff --git a/client/api_basic.go b/client/api_basic.go index 4506ba11..11bde38e 100644 --- a/client/api_basic.go +++ b/client/api_basic.go @@ -3,6 +3,8 @@ package client import ( "context" "fmt" + "io" + "os" "strings" "time" @@ -20,8 +22,10 @@ import ( "google.golang.org/grpc" ) -// Basic interface defines basic functions of greenfield client. -type Basic interface { +// IBasicClient interface defines basic functions of greenfield Client. +type IBasicClient interface { + EnableTrace(outputStream io.Writer, onlyTraceErr bool) + GetNodeInfo(ctx context.Context) (*p2p.DefaultNodeInfo, *tmservice.VersionInfo, error) GetStatus(ctx context.Context) (*ctypes.ResultStatus, error) @@ -49,9 +53,28 @@ type Basic interface { QueryVote(ctx context.Context, eventType int, eventHash []byte) (*ctypes.ResultQueryVote, error) } -// GetNodeInfo returns the current node info of the greenfield that the client is connected to. -// It takes a context as input and returns a ResultStatus object and an error (if any). -func (c *client) GetNodeInfo(ctx context.Context) (*p2p.DefaultNodeInfo, *tmservice.VersionInfo, error) { +// EnableTrace support trace error info the request and the response +func (c *Client) EnableTrace(output io.Writer, onlyTraceErr bool) { + if output == nil { + output = os.Stdout + } + + c.onlyTraceError = onlyTraceErr + + c.traceOutput = output + c.isTraceEnabled = true +} + +// GetNodeInfo - Get the current node info of the greenfield that the Client is connected to. +// +// - ctx: Context variables for the current API call. +// +// - ret1: The Node info. +// +// - ret2: The Version info. +// +// - ret3: Return error when the request failed, otherwise return nil. +func (c *Client) GetNodeInfo(ctx context.Context) (*p2p.DefaultNodeInfo, *tmservice.VersionInfo, error) { nodeInfoResponse, err := c.chainClient.TmClient.GetNodeInfo(ctx, &tmservice.GetNodeInfoRequest{}) if err != nil { return nil, nil, err @@ -59,19 +82,42 @@ func (c *client) GetNodeInfo(ctx context.Context) (*p2p.DefaultNodeInfo, *tmserv return nodeInfoResponse.DefaultNodeInfo, nodeInfoResponse.ApplicationVersion, nil } -func (c *client) GetStatus(ctx context.Context) (*ctypes.ResultStatus, error) { +// GetStatus - Get the status of connected Node. +// +// - ctx: Context variables for the current API call. +// +// - ret1: The detail of Node status. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetStatus(ctx context.Context) (*ctypes.ResultStatus, error) { return c.chainClient.GetStatus(ctx) } -func (c *client) GetCommit(ctx context.Context, height int64) (*ctypes.ResultCommit, error) { +// GetCommit - Get the block commit detail. +// +// - ctx: Context variables for the current API call. +// +// - height: The block height. +// +// - ret1: The commit result. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetCommit(ctx context.Context, height int64) (*ctypes.ResultCommit, error) { return c.chainClient.GetCommit(ctx, height) } -// BroadcastRawTx broadcasts raw transaction bytes to a Tendermint node. -// It takes a context, transaction bytes, and a sync boolean. -// If sync is true, the transaction is broadcast synchronously. -// If sync is false, the transaction is broadcast asynchronously. -func (c *client) BroadcastRawTx(ctx context.Context, txBytes []byte, sync bool) (*sdk.TxResponse, error) { +// BroadcastRawTx - Broadcast raw transaction bytes to a Tendermint node. +// +// - ctx: Context variables for the current API call. +// +// - txBytes: The transaction bytes. +// +// - sync: A flag to specify the transaction mode. If it is true, the transaction is broadcast synchronously. If it is false, the transaction is broadcast asynchronously. +// +// - ret1: Transaction response, it can indicate both success and failed transaction. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) BroadcastRawTx(ctx context.Context, txBytes []byte, sync bool) (*sdk.TxResponse, error) { var mode tx.BroadcastMode if sync { mode = tx.BroadcastMode_BROADCAST_MODE_SYNC @@ -85,10 +131,18 @@ func (c *client) BroadcastRawTx(ctx context.Context, txBytes []byte, sync bool) return broadcastTxResponse.TxResponse, nil } -// SimulateRawTx simulates the execution of a raw transaction on the blockchain without broadcasting it to the network. -// It takes a context, transaction bytes, and any additional gRPC call options. -// It returns a SimulateResponse object and an error (if any). -func (c *client) SimulateRawTx(ctx context.Context, txBytes []byte, opts ...grpc.CallOption) (*tx.SimulateResponse, error) { +// SimulateRawTx - Simulate the execution of a raw transaction on the blockchain without broadcasting it to the network. +// +// - ctx: Context variables for the current API call. +// +// - txBytes: The transaction bytes. +// +// - opts: The grpc option(s) if Client is using grpc connection. +// +// - ret1: The simulation result. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) SimulateRawTx(ctx context.Context, txBytes []byte, opts ...grpc.CallOption) (*tx.SimulateResponse, error) { simulateResponse, err := c.chainClient.TxClient.Simulate( ctx, &tx.SimulateRequest{ @@ -102,9 +156,14 @@ func (c *client) SimulateRawTx(ctx context.Context, txBytes []byte, opts ...grpc return simulateResponse, nil } -// GetLatestBlock retrieves the latest block from the chain. -// The function returns a pointer to a Block object and any error that occurred during the operation. -func (c *client) GetLatestBlock(ctx context.Context) (*bfttypes.Block, error) { +// GetLatestBlock - Get the latest block from the chain. +// +// - ctx: Context variables for the current API call. +// +// - ret1: The block result. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetLatestBlock(ctx context.Context) (*bfttypes.Block, error) { res, err := c.chainClient.GetBlock(ctx, nil) if err != nil { return nil, err @@ -112,9 +171,14 @@ func (c *client) GetLatestBlock(ctx context.Context) (*bfttypes.Block, error) { return res.Block, nil } -// GetLatestBlockHeight retrieves the height of the latest block from the chain. -// The function returns the block height and any error that occurred during the operation. -func (c *client) GetLatestBlockHeight(ctx context.Context) (int64, error) { +// GetLatestBlockHeight - Get the height of the latest block from the chain. +// +// - ctx: Context variables for the current API call. +// +// - ret1: The block height. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetLatestBlockHeight(ctx context.Context) (int64, error) { resp, err := c.GetLatestBlock(ctx) if err != nil { return 0, nil @@ -122,9 +186,12 @@ func (c *client) GetLatestBlockHeight(ctx context.Context) (int64, error) { return resp.Header.Height, nil } -// WaitForBlockHeight waits until block height h is committed, or returns an -// error if ctx is canceled. -func (c *client) WaitForBlockHeight(ctx context.Context, h int64) error { +// WaitForBlockHeight - Wait until a specified block height is committed. +// +// - ctx: Context variables for the current API call. +// +// - ret: Return error when the request failed, otherwise return nil. +func (c *Client) WaitForBlockHeight(ctx context.Context, h int64) error { ticker := time.NewTicker(time.Second) defer ticker.Stop() @@ -144,16 +211,23 @@ func (c *client) WaitForBlockHeight(ctx context.Context, h int64) error { } } -// WaitForNextBlock waits until next block is committed. -// It reads the current block height and then waits for another block to be -// committed, or returns an error if ctx is canceled. -func (c *client) WaitForNextBlock(ctx context.Context) error { +// WaitForNextBlock - Wait until the next block is committed since current block. +// +// - ctx: Context variables for the current API call. +// +// - ret: Return error when the request failed, otherwise return nil. +func (c *Client) WaitForNextBlock(ctx context.Context) error { return c.WaitForNBlocks(ctx, 1) } -// WaitForNBlocks reads the current block height and then waits for another n -// blocks to be committed, or returns an error if ctx is canceled. -func (c *client) WaitForNBlocks(ctx context.Context, n int64) error { +// WaitForNBlocks - Wait for another n blocks to be committed since current block. +// +// - ctx: Context variables for the current API call. +// +// - n: number of blocks to be waited. +// +// - ret: Return error when the request failed, otherwise return nil. +func (c *Client) WaitForNBlocks(ctx context.Context, n int64) error { start, err := c.GetLatestBlock(ctx) if err != nil { return err @@ -161,9 +235,16 @@ func (c *client) WaitForNBlocks(ctx context.Context, n int64) error { return c.WaitForBlockHeight(ctx, start.Header.Height+n) } -// WaitForTx requests the tx from hash, if not found, waits for next block and -// tries again. Returns an error if ctx is canceled. -func (c *client) WaitForTx(ctx context.Context, hash string) (*ctypes.ResultTx, error) { +// WaitForTx - Wait for a transaction to be confirmed onchian, if transaction not found in current block, wait for the next block. API ends when a transaction is found or context is canceled. +// +// - ctx: Context variables for the current API call. +// +// - hash: The hex representation of transaction hash. +// +// - ret1: The transaction result details. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) WaitForTx(ctx context.Context, hash string) (*ctypes.ResultTx, error) { for { var ( txResponse *ctypes.ResultTx @@ -206,9 +287,20 @@ func (c *client) WaitForTx(ctx context.Context, hash string) (*ctypes.ResultTx, } } -// BroadcastTx broadcasts a transaction containing the provided messages to the chain. -// The function returns a pointer to a BroadcastTxResponse and any error that occurred during the operation. -func (c *client) BroadcastTx(ctx context.Context, msgs []sdk.Msg, txOpt *types.TxOption, opts ...grpc.CallOption) (*tx.BroadcastTxResponse, error) { +// BroadcastTx - Broadcast a transaction containing the provided message(s) to the chain. +// +// - ctx: Context variables for the current API call. +// +// - msgs: Message(s) to be broadcast to blockchain. +// +// - txOpt: txOpt contains options for customizing the transaction. +// +// - opts: The grpc option(s) if Client is using grpc connection. +// +// - ret1: transaction response, it can indicate both success and failed transaction. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) BroadcastTx(ctx context.Context, msgs []sdk.Msg, txOpt *types.TxOption, opts ...grpc.CallOption) (*tx.BroadcastTxResponse, error) { resp, err := c.chainClient.BroadcastTx(ctx, msgs, txOpt, opts...) if err != nil { return nil, err @@ -219,15 +311,31 @@ func (c *client) BroadcastTx(ctx context.Context, msgs []sdk.Msg, txOpt *types.T return resp, nil } -// SimulateTx simulates a transaction containing the provided messages on the chain. -// The function returns a pointer to a SimulateResponse and any error that occurred during the operation. -func (c *client) SimulateTx(ctx context.Context, msgs []sdk.Msg, txOpt types.TxOption, opts ...grpc.CallOption) (*tx.SimulateResponse, error) { +// SimulateTx - Simulate a transaction containing the provided message(s) on the chain. +// +// - ctx: Context variables for the current API call. +// +// - msgs: Message(s) to be broadcast to blockchain. +// +// - txOpt: TxOpt contains options for customizing the transaction. +// +// - opts: The grpc option(s) if Client is using grpc connection. +// +// - ret1: The simulation result. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) SimulateTx(ctx context.Context, msgs []sdk.Msg, txOpt types.TxOption, opts ...grpc.CallOption) (*tx.SimulateResponse, error) { return c.chainClient.SimulateTx(ctx, msgs, &txOpt, opts...) } -// GetSyncing retrieves the syncing status of the node. If true, means the node is catching up the latest block. -// The function returns a boolean indicating whether the node is syncing and any error that occurred during the operation. -func (c *client) GetSyncing(ctx context.Context) (bool, error) { +// GetSyncing - Retrieve the syncing status of the node. +// +// - ctx: Context variables for the current API call. +// +// - ret1: The boolean value which indicates whether the node has caught up the latest block. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetSyncing(ctx context.Context) (bool, error) { syncing, err := c.chainClient.GetSyncing(ctx, &tmservice.GetSyncingRequest{}) if err != nil { return false, err @@ -235,9 +343,16 @@ func (c *client) GetSyncing(ctx context.Context) (bool, error) { return syncing.Syncing, nil } -// GetBlockByHeight retrieves the block at the given height from the chain. -// The function returns a pointer to a Block object and any error that occurred during the operation. -func (c *client) GetBlockByHeight(ctx context.Context, height int64) (*bfttypes.Block, error) { +// GetBlockByHeight - Retrieve the block at the given height from the chain. +// +// - ctx: Context variables for the current API call. +// +// - height: The block height. +// +// - ret1: The boolean value which indicates whether the node has caught up the latest block. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetBlockByHeight(ctx context.Context, height int64) (*bfttypes.Block, error) { blockByHeight, err := c.chainClient.GetBlock(ctx, &height) if err != nil { return nil, err @@ -245,12 +360,29 @@ func (c *client) GetBlockByHeight(ctx context.Context, height int64) (*bfttypes. return blockByHeight.Block, nil } -func (c *client) GetBlockResultByHeight(ctx context.Context, height int64) (*ctypes.ResultBlockResults, error) { +// GetBlockResultByHeight - Retrieve the block result at the given height from the chain. +// +// - ctx: Context variables for the current API call. +// +// - height: The block height. +// +// - ret1: The boolean value which indicates whether the node has caught up the latest block. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetBlockResultByHeight(ctx context.Context, height int64) (*ctypes.ResultBlockResults, error) { return c.chainClient.GetBlockResults(ctx, &height) } -// GetValidatorSet retrieves the latest validator set from the chain. -func (c *client) GetValidatorSet(ctx context.Context) (int64, []*bfttypes.Validator, error) { +// GetValidatorSet - Retrieve the latest validator set from the chain. +// +// - ctx: Context variables for the current API call. +// +// - ret1: The latest height of block that validators set info retrieved from. +// +// - ret2: The list of validators. +// +// - ret3: Return error when the request failed, otherwise return nil. +func (c *Client) GetValidatorSet(ctx context.Context) (int64, []*bfttypes.Validator, error) { validatorSetResponse, err := c.chainClient.GetValidators(ctx, nil) if err != nil { return 0, nil, err @@ -258,8 +390,16 @@ func (c *client) GetValidatorSet(ctx context.Context) (int64, []*bfttypes.Valida return validatorSetResponse.BlockHeight, validatorSetResponse.Validators, nil } -// GetValidatorsByHeight retrieves the validator set from the chain. -func (c *client) GetValidatorsByHeight(ctx context.Context, height int64) ([]*bfttypes.Validator, error) { +// GetValidatorsByHeight - Retrieve the validator set at a given block height from the chain. +// +// - ctx: Context variables for the current API call. +// +// - height: The block height. +// +// - ret1: The list of validators. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetValidatorsByHeight(ctx context.Context, height int64) ([]*bfttypes.Validator, error) { validatorSetResponse, err := c.chainClient.GetValidators(ctx, &height) if err != nil { return nil, err @@ -267,10 +407,28 @@ func (c *client) GetValidatorsByHeight(ctx context.Context, height int64) ([]*bf return validatorSetResponse.Validators, nil } -func (c *client) BroadcastVote(ctx context.Context, vote votepool.Vote) error { +// BroadcastVote - Broadcast a vote to the Node's VotePool, it is used by Greenfield relayer and challengers by now. +// +// - ctx: Context variables for the current API call. +// +// - vote: Contains vote details. +// +// - ret: Return error when the request failed, otherwise return nil. +func (c *Client) BroadcastVote(ctx context.Context, vote votepool.Vote) error { return c.chainClient.BroadcastVote(ctx, vote) } -func (c *client) QueryVote(ctx context.Context, eventType int, eventHash []byte) (*ctypes.ResultQueryVote, error) { +// QueryVote - Query a vote from the Node's VotePool, it is used by Greenfield relayer and challengers by now. +// +// - ctx: Context variables for the current API call. +// +// - eventType: The type of vote to be queried. +// +// - eventHash: The hash bytes of vote +// +// - ret1: The vote result +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) QueryVote(ctx context.Context, eventType int, eventHash []byte) (*ctypes.ResultQueryVote, error) { return c.chainClient.QueryVote(ctx, eventType, eventHash) } diff --git a/client/api_bucket.go b/client/api_bucket.go index bcbe2301..f33db4f0 100644 --- a/client/api_bucket.go +++ b/client/api_bucket.go @@ -6,7 +6,6 @@ import ( "encoding/xml" "errors" "fmt" - govTypes "github.com/cosmos/cosmos-sdk/x/gov/types" "io" "math" "net/http" @@ -22,56 +21,50 @@ import ( storageTypes "github.com/bnb-chain/greenfield/x/storage/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx" + govTypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/rs/zerolog/log" "github.com/bnb-chain/greenfield-go-sdk/pkg/utils" "github.com/bnb-chain/greenfield-go-sdk/types" ) -type Bucket interface { +// IBucketClient interface defines functions related to bucket. +// The concept of "bucket" is the same as the concept of a bucket in AWS S3 storage. +type IBucketClient interface { GetCreateBucketApproval(ctx context.Context, createBucketMsg *storageTypes.MsgCreateBucket) (*storageTypes.MsgCreateBucket, error) - // CreateBucket get approval of creating bucket and send createBucket txn to greenfield chain - // primaryAddr indicates the HEX-encoded string of the primary storage provider address to which the bucket will be created CreateBucket(ctx context.Context, bucketName string, primaryAddr string, opts types.CreateBucketOptions) (string, error) DeleteBucket(ctx context.Context, bucketName string, opt types.DeleteBucketOption) (string, error) - UpdateBucketVisibility(ctx context.Context, bucketName string, visibility storageTypes.VisibilityType, opt types.UpdateVisibilityOption) (string, error) UpdateBucketInfo(ctx context.Context, bucketName string, opts types.UpdateBucketOptions) (string, error) UpdateBucketPaymentAddr(ctx context.Context, bucketName string, paymentAddr sdk.AccAddress, opt types.UpdatePaymentOption) (string, error) - HeadBucket(ctx context.Context, bucketName string) (*storageTypes.BucketInfo, error) HeadBucketByID(ctx context.Context, bucketID string) (*storageTypes.BucketInfo, error) - // PutBucketPolicy put the bucket policy to the principal, return the txn hash - // the principal can be generated by NewPrincipalWithAccount or NewPrincipalWithGroupId PutBucketPolicy(ctx context.Context, bucketName string, principal types.Principal, statements []*permTypes.Statement, opt types.PutPolicyOption) (string, error) - // DeleteBucketPolicy delete the bucket policy of the principal,return the txn hash - // the principal can be generated by NewPrincipalWithAccount or NewPrincipalWithGroupId DeleteBucketPolicy(ctx context.Context, bucketName string, principal types.Principal, opt types.DeletePolicyOption) (string, error) - // GetBucketPolicy get the bucket policy info of the user specified by principalAddr. - // principalAddr indicates the HEX-encoded string of the principal address GetBucketPolicy(ctx context.Context, bucketName string, principalAddr string) (*permTypes.Policy, error) - // IsBucketPermissionAllowed check if the permission of bucket is allowed to the user. - // userAddr indicates the HEX-encoded string of the user address IsBucketPermissionAllowed(ctx context.Context, userAddr string, bucketName string, action permTypes.ActionType) (permTypes.Effect, error) - ListBuckets(ctx context.Context, opts types.ListBucketsOptions) (types.ListBucketsResult, error) ListBucketReadRecord(ctx context.Context, bucketName string, opts types.ListReadRecordOptions) (types.QuotaRecordInfo, error) - GetQuotaUpdateTime(ctx context.Context, bucketName string) (int64, error) BuyQuotaForBucket(ctx context.Context, bucketName string, targetQuota uint64, opt types.BuyQuotaOption) (string, error) GetBucketReadQuota(ctx context.Context, bucketName string) (types.QuotaInfo, error) - - // ListBucketsByBucketID list buckets by bucket ids ListBucketsByBucketID(ctx context.Context, bucketIds []uint64, opts types.EndPointOptions) (types.ListBucketsByBucketIDResponse, error) GetMigrateBucketApproval(ctx context.Context, migrateBucketMsg *storageTypes.MsgMigrateBucket) (*storageTypes.MsgMigrateBucket, error) - MigrateBucket(ctx context.Context, bucketName string, opts types.MigrateBucketOptions) (string, error) + MigrateBucket(ctx context.Context, bucketName string, dstPrimarySPID uint32, opts types.MigrateBucketOptions) (string, error) CancelMigrateBucket(ctx context.Context, bucketName string, opts types.CancelMigrateBucketOptions) (uint64, string, error) - // ListBucketsByPaymentAccount list buckets by payment account ListBucketsByPaymentAccount(ctx context.Context, paymentAccount string, opts types.ListBucketsByPaymentAccountOptions) (types.ListBucketsByPaymentAccountResult, error) } -// GetCreateBucketApproval returns the signature info for the approval of preCreating resources -func (c *client) GetCreateBucketApproval(ctx context.Context, createBucketMsg *storageTypes.MsgCreateBucket) (*storageTypes.MsgCreateBucket, error) { +// GetCreateBucketApproval - Send create bucket approval request to SP and returns the signature info for the approval of preCreating resources. +// +// - ctx: Context variables for the current API call. +// +// - createBucketMsg: The msg of create bucket which defined by the greenfield chain. +// +// - ret1: The msg of create bucket which contain the approval signature from the storage provider +// +// - ret2: Return error when get approval failed, otherwise return nil. +func (c *Client) GetCreateBucketApproval(ctx context.Context, createBucketMsg *storageTypes.MsgCreateBucket) (*storageTypes.MsgCreateBucket, error) { unsignedBytes := createBucketMsg.GetSignBytes() // set the action type @@ -119,8 +112,22 @@ func (c *client) GetCreateBucketApproval(ctx context.Context, createBucketMsg *s return &signedMsg, nil } -// CreateBucket get approval of creating bucket and send createBucket txn to greenfield chain, it returns the transaction hash value and error -func (c *client) CreateBucket(ctx context.Context, bucketName string, primaryAddr string, opts types.CreateBucketOptions) (string, error) { +// CreateBucket - Create a new bucket in greenfield. +// +// This API sends a request to the storage provider to get approval for creating bucket and sends the createBucket transaction to the Greenfield. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The name of the bucket to be created. +// +// - primaryAddr: The primary SP address to which the bucket will be created on. +// +// - opts: The Options indicates the meta to construct createBucket msg and the way to send transaction +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error if create bucket failed, otherwise return nil. +func (c *Client) CreateBucket(ctx context.Context, bucketName string, primaryAddr string, opts types.CreateBucketOptions) (string, error) { address, err := sdk.AccAddressFromHexUnsafe(primaryAddr) if err != nil { return "", err @@ -177,8 +184,18 @@ func (c *client) CreateBucket(ctx context.Context, bucketName string, primaryAdd return txnHash, nil } -// DeleteBucket send DeleteBucket txn to greenfield chain and return txn hash -func (c *client) DeleteBucket(ctx context.Context, bucketName string, opt types.DeleteBucketOption) (string, error) { +// DeleteBucket - Send DeleteBucket msg to greenfield chain and return txn hash. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The name of the bucket to be deleted +// +// - opt: The Options for customizing the transaction. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error if delete bucket failed, otherwise return nil. +func (c *Client) DeleteBucket(ctx context.Context, bucketName string, opt types.DeleteBucketOption) (string, error) { if err := s3util.CheckValidBucketName(bucketName); err != nil { return "", err } @@ -186,8 +203,20 @@ func (c *client) DeleteBucket(ctx context.Context, bucketName string, opt types. return c.sendTxn(ctx, delBucketMsg, opt.TxOpts) } -// UpdateBucketVisibility update the visibilityType of bucket -func (c *client) UpdateBucketVisibility(ctx context.Context, bucketName string, +// UpdateBucketVisibility - Update the visibilityType of bucket. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The name of the bucket to be updated. +// +// - visibility: The VisibilityType defines on greenfield which can be PUBLIC_READ, PRIVATE or INHERIT +// +// - opt: The Options for customizing the transaction. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error if update visibility failed, otherwise return nil. +func (c *Client) UpdateBucketVisibility(ctx context.Context, bucketName string, visibility storageTypes.VisibilityType, opt types.UpdateVisibilityOption, ) (string, error) { bucketInfo, err := c.HeadBucket(ctx, bucketName) @@ -204,8 +233,20 @@ func (c *client) UpdateBucketVisibility(ctx context.Context, bucketName string, return c.sendTxn(ctx, updateBucketMsg, opt.TxOpts) } -// UpdateBucketPaymentAddr update the payment addr of bucket -func (c *client) UpdateBucketPaymentAddr(ctx context.Context, bucketName string, +// UpdateBucketPaymentAddr - Update the payment address of bucket. It will send the MsgUpdateBucketInfo msg to greenfield to update the meta. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The name of the bucket to be updated. +// +// - paymentAddr: The payment address from which deduct the cost of bucket storage or quota. +// +// - opt: The Options for customizing the transaction. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error if update payment address failed, otherwise return nil. +func (c *Client) UpdateBucketPaymentAddr(ctx context.Context, bucketName string, paymentAddr sdk.AccAddress, opt types.UpdatePaymentOption, ) (string, error) { bucketInfo, err := c.HeadBucket(ctx, bucketName) @@ -217,8 +258,20 @@ func (c *client) UpdateBucketPaymentAddr(ctx context.Context, bucketName string, return c.sendTxn(ctx, updateBucketMsg, opt.TxOpts) } -// UpdateBucketInfo update the bucket meta on chain, including read quota, payment address or visibility -func (c *client) UpdateBucketInfo(ctx context.Context, bucketName string, opts types.UpdateBucketOptions) (string, error) { +// UpdateBucketInfo - Update the bucket meta on chain, including read quota, payment address or visibility. It will send the MsgUpdateBucketInfo msg to greenfield to update the meta. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The name of the bucket to be updated. +// +// - paymentAddr: The payment address from which deduct the cost of bucket storage or quota. +// +// - opts: The Options used to specify which metas need to be updated and the option to send transaction. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error if update bucket meta failed, otherwise return nil. +func (c *Client) UpdateBucketInfo(ctx context.Context, bucketName string, opts types.UpdateBucketOptions) (string, error) { bucketInfo, err := c.HeadBucket(ctx, bucketName) if err != nil { return "", err @@ -268,9 +321,16 @@ func (c *client) UpdateBucketInfo(ctx context.Context, bucketName string, opts t return c.sendTxn(ctx, updateBucketMsg, opts.TxOpts) } -// HeadBucket query the bucketInfo on chain, return the bucket info if exists -// return err info if bucket not exist -func (c *client) HeadBucket(ctx context.Context, bucketName string) (*storageTypes.BucketInfo, error) { +// HeadBucket - query the bucketInfo on chain by bucket name, return the bucket info if exists. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The name of the bucket to query. +// +// - ret1: The bucket specific metadata information, including Visibility, payment address, charged quota and so on. +// +// - ret2: Return error if bucket not exist, otherwise return nil. +func (c *Client) HeadBucket(ctx context.Context, bucketName string) (*storageTypes.BucketInfo, error) { queryHeadBucketRequest := storageTypes.QueryHeadBucketRequest{ BucketName: bucketName, } @@ -282,9 +342,16 @@ func (c *client) HeadBucket(ctx context.Context, bucketName string) (*storageTyp return queryHeadBucketResponse.BucketInfo, nil } -// HeadBucketByID query the bucketInfo on chain by bucketId, return the bucket info if exists -// return err info if bucket not exist -func (c *client) HeadBucketByID(ctx context.Context, bucketID string) (*storageTypes.BucketInfo, error) { +// HeadBucketByID - query the bucketInfo on chain by the bucket id, return the bucket info if exists. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The name of the bucket to query. +// +// - ret1: The bucket specific metadata information, including Visibility, payment address, charged quota and so on. +// +// - ret2: Return error if bucket not exist, otherwise return nil. +func (c *Client) HeadBucketByID(ctx context.Context, bucketID string) (*storageTypes.BucketInfo, error) { headBucketRequest := &storageTypes.QueryHeadBucketByIdRequest{ BucketId: bucketID, } @@ -297,8 +364,22 @@ func (c *client) HeadBucketByID(ctx context.Context, bucketID string) (*storageT return headBucketResponse.BucketInfo, nil } -// PutBucketPolicy apply bucket policy to the principal, return the txn hash -func (c *client) PutBucketPolicy(ctx context.Context, bucketName string, principalStr types.Principal, +// PutBucketPolicy - Apply bucket policy to the principal, return the txn hash. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The bucket name identifies the bucket. +// +// - principalStr: Indicates the marshaled principal content of greenfield permission types, users can generate it by NewPrincipalWithAccount or NewPrincipalWithGroupId method. +// +// - statements: Policies outline the specific details of permissions, including the Effect, ActionList, and Resources. +// +// - opt: The options for customizing the policy expiration time and transaction. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) PutBucketPolicy(ctx context.Context, bucketName string, principalStr types.Principal, statements []*permTypes.Statement, opt types.PutPolicyOption, ) (string, error) { resource := gnfdTypes.NewBucketGRN(bucketName) @@ -313,8 +394,20 @@ func (c *client) PutBucketPolicy(ctx context.Context, bucketName string, princip return c.sendPutPolicyTxn(ctx, putPolicyMsg, opt.TxOpts) } -// DeleteBucketPolicy delete the bucket policy of the principal -func (c *client) DeleteBucketPolicy(ctx context.Context, bucketName string, principalStr types.Principal, opt types.DeletePolicyOption) (string, error) { +// DeleteBucketPolicy - Delete the bucket policy of the principal. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The bucket name identifies the bucket. +// +// - principalStr: Indicates the marshaled principal content of greenfield permission types, users can generate it by NewPrincipalWithAccount or NewPrincipalWithGroupId method. +// +// - opt: The option for send delete policy transaction. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) DeleteBucketPolicy(ctx context.Context, bucketName string, principalStr types.Principal, opt types.DeletePolicyOption) (string, error) { resource := gnfdTypes.NewBucketGRN(bucketName).String() principal := &permTypes.Principal{} if err := principal.Unmarshal([]byte(principalStr)); err != nil { @@ -324,8 +417,20 @@ func (c *client) DeleteBucketPolicy(ctx context.Context, bucketName string, prin return c.sendDelPolicyTxn(ctx, c.MustGetDefaultAccount().GetAddress(), resource, principal, opt.TxOpts) } -// IsBucketPermissionAllowed check if the permission of bucket is allowed to the user. -func (c *client) IsBucketPermissionAllowed(ctx context.Context, userAddr string, +// IsBucketPermissionAllowed - Check if the permission of bucket is allowed to the user. +// +// - ctx: Context variables for the current API call. +// +// - userAddr: The HEX-encoded string of the user address +// +// - bucketName: The bucket name identifies the bucket. +// +// - action: Indicates the permission corresponding to which type of action needs to be verified +// +// - ret1: Return EFFECT_ALLOW if the permission is allowed and EFFECT_DENY if the permission is denied +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) IsBucketPermissionAllowed(ctx context.Context, userAddr string, bucketName string, action permTypes.ActionType, ) (permTypes.Effect, error) { _, err := sdk.AccAddressFromHexUnsafe(userAddr) @@ -346,8 +451,16 @@ func (c *client) IsBucketPermissionAllowed(ctx context.Context, userAddr string, return verifyResp.Effect, nil } -// GetBucketPolicy get the bucket policy info of the user specified by principalAddr. -func (c *client) GetBucketPolicy(ctx context.Context, bucketName string, principalAddr string) (*permTypes.Policy, error) { +// GetBucketPolicy - Get the bucket policy info of the user specified by principalAddr. +// +// - bucketName: The bucket name identifies the bucket. +// +// - principalAddr: The HEX-encoded string of the principal address. +// +// - ret1: The bucket policy info defined on greenfield. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetBucketPolicy(ctx context.Context, bucketName string, principalAddr string) (*permTypes.Policy, error) { _, err := sdk.AccAddressFromHexUnsafe(principalAddr) if err != nil { return nil, err @@ -367,17 +480,17 @@ func (c *client) GetBucketPolicy(ctx context.Context, bucketName string, princip return queryPolicyResp.Policy, nil } -type GfSpListBucketsByIDsResponse map[uint64]*types.BucketMeta +type listBucketsByIDsResponse map[uint64]*types.BucketMeta -type BucketEntry struct { +type bucketEntry struct { Id uint64 Value *types.BucketMeta } -func (m *GfSpListBucketsByIDsResponse) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { - *m = GfSpListBucketsByIDsResponse{} +func (m *listBucketsByIDsResponse) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *m = listBucketsByIDsResponse{} for { - var e BucketEntry + var e bucketEntry err := d.Decode(&e) if err == io.EOF { @@ -391,8 +504,18 @@ func (m *GfSpListBucketsByIDsResponse) UnmarshalXML(d *xml.Decoder, start xml.St return nil } -// ListBuckets list buckets for the owner -func (c *client) ListBuckets(ctx context.Context, opts types.ListBucketsOptions) (types.ListBucketsResult, error) { +// ListBuckets - Lists the bucket info of the user. +// +// If the opts.Account is not set, the user is default set as the sender. +// +// - ctx: Context variables for the current API call. +// +// - opts: The options to set the meta to list the bucket +// +// - ret1: The result of list bucket under specific user address +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) ListBuckets(ctx context.Context, opts types.ListBucketsOptions) (types.ListBucketsResult, error) { params := url.Values{} params.Set("include-removed", strconv.FormatBool(opts.ShowRemovedBucket)) @@ -458,9 +581,18 @@ func (c *client) ListBuckets(ctx context.Context, opts types.ListBucketsOptions) return listBucketsResult, nil } -// ListBucketReadRecord returns the read record of this month, the return items should be no more than maxRecords -// ListReadRecordOption indicates the start timestamp of return read records -func (c *client) ListBucketReadRecord(ctx context.Context, bucketName string, opts types.ListReadRecordOptions) (types.QuotaRecordInfo, error) { +// ListBucketReadRecord - List the download record info of the specific bucket of the current month. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The bucket name identifies the bucket. +// +// - opts: Indicates the start timestamp of return read records and the max number of return items +// +// - ret1: The read record info of the bucket returned by SP. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) ListBucketReadRecord(ctx context.Context, bucketName string, opts types.ListReadRecordOptions) (types.QuotaRecordInfo, error) { if err := s3util.CheckValidBucketName(bucketName); err != nil { return types.QuotaRecordInfo{}, err } @@ -527,8 +659,16 @@ func (c *client) ListBucketReadRecord(ctx context.Context, bucketName string, op return QuotaRecords, nil } -// GetBucketReadQuota return quota info of bucket of current month, include chain quota, free quota and consumed quota -func (c *client) GetBucketReadQuota(ctx context.Context, bucketName string) (types.QuotaInfo, error) { +// GetBucketReadQuota - Query the quota info of the specific bucket of current month. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The bucket name identifies the bucket. +// +// - ret1: The info of quota which contains the consumed quota, the charged quota and free quota info of the bucket +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetBucketReadQuota(ctx context.Context, bucketName string) (types.QuotaInfo, error) { if err := s3util.CheckValidBucketName(bucketName); err != nil { return types.QuotaInfo{}, err } @@ -578,7 +718,16 @@ func (c *client) GetBucketReadQuota(ctx context.Context, bucketName string) (typ return QuotaResult, nil } -func (c *client) GetQuotaUpdateTime(ctx context.Context, bucketName string) (int64, error) { +// GetQuotaUpdateTime - Query the update time stamp of the bucket quota info. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The bucket name identifies the bucket. +// +// - ret1: The update time stamp. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetQuotaUpdateTime(ctx context.Context, bucketName string) (int64, error) { resp, err := c.chainClient.QueryQuotaUpdateTime(ctx, &storageTypes.QueryQuoteUpdateTimeRequest{ BucketName: bucketName, }) @@ -588,9 +737,18 @@ func (c *client) GetQuotaUpdateTime(ctx context.Context, bucketName string) (int return resp.UpdateAt, nil } -// BuyQuotaForBucket buy the target quota of the specific bucket -// targetQuota indicates the target quota to set for the bucket -func (c *client) BuyQuotaForBucket(ctx context.Context, bucketName string, targetQuota uint64, opt types.BuyQuotaOption) (string, error) { +// BuyQuotaForBucket - Buy the target quota for the specific bucket. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The bucket name identifies the bucket. +// +// - targetQuota: Indicates the target quota value after setting, and can only be set to a higher value than the current value. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) BuyQuotaForBucket(ctx context.Context, bucketName string, targetQuota uint64, opt types.BuyQuotaOption) (string, error) { bucketInfo, err := c.HeadBucket(ctx, bucketName) if err != nil { return "", err @@ -610,10 +768,20 @@ func (c *client) BuyQuotaForBucket(ctx context.Context, bucketName string, targe return resp.TxResponse.TxHash, err } -// ListBucketsByBucketID list buckets by bucket ids -// By inputting a collection of bucket IDs, we can retrieve the corresponding bucket data. -// If the bucket is nonexistent or has been deleted, a null value will be returned -func (c *client) ListBucketsByBucketID(ctx context.Context, bucketIds []uint64, opts types.EndPointOptions) (types.ListBucketsByBucketIDResponse, error) { +// ListBucketsByBucketID - List buckets by bucket ids. +// +// By inputting a collection of bucket IDs, we can retrieve the corresponding bucket data. If the bucket is nonexistent or has been deleted, a null value will be returned +// +// - ctx: Context variables for the current API call. +// +// - bucketIds: The list of bucket ids. +// +// - opts: The options to set the meta to list buckets by bucket id. +// +// - ret1: The result of bucket info map by given bucket ids. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) ListBucketsByBucketID(ctx context.Context, bucketIds []uint64, opts types.EndPointOptions) (types.ListBucketsByBucketIDResponse, error) { const MaximumListBucketsSize = 1000 if len(bucketIds) == 0 || len(bucketIds) > MaximumListBucketsSize { return types.ListBucketsByBucketIDResponse{}, nil @@ -671,7 +839,7 @@ func (c *client) ListBucketsByBucketID(ctx context.Context, bucketIds []uint64, buckets := types.ListBucketsByBucketIDResponse{} bufStr := buf.String() - err = xml.Unmarshal([]byte(bufStr), (*GfSpListBucketsByIDsResponse)(&buckets.Buckets)) + err = xml.Unmarshal([]byte(bufStr), (*listBucketsByIDsResponse)(&buckets.Buckets)) if err != nil && buckets.Buckets == nil { log.Error().Msgf("the list of buckets in bucket ids:%v failed: %s", bucketIds, err.Error()) return types.ListBucketsByBucketIDResponse{}, err @@ -680,7 +848,16 @@ func (c *client) ListBucketsByBucketID(ctx context.Context, bucketIds []uint64, return buckets, nil } -func (c *client) GetMigrateBucketApproval(ctx context.Context, migrateBucketMsg *storageTypes.MsgMigrateBucket) (*storageTypes.MsgMigrateBucket, error) { +// GetMigrateBucketApproval - Send migrate get approval request to the storage provider and return the signed MsgMigrateBucket by SP. +// +// - ctx: Context variables for the current API call. +// +// - migrateBucketMsg: Indicates msg of migrating bucket which defined by greenfield +// +// - ret1: The msg of migrating bucket which contain the approval signature from the storage provider. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetMigrateBucketApproval(ctx context.Context, migrateBucketMsg *storageTypes.MsgMigrateBucket) (*storageTypes.MsgMigrateBucket, error) { unsignedBytes := migrateBucketMsg.GetSignBytes() // set the action type @@ -727,9 +904,21 @@ func (c *client) GetMigrateBucketApproval(ctx context.Context, migrateBucketMsg return &signedMsg, nil } -// MigrateBucket get approval of migrating bucket and send migrateBucket txn to greenfield chain, it returns the transaction hash value and error -func (c *client) MigrateBucket(ctx context.Context, bucketName string, opts types.MigrateBucketOptions) (string, error) { - migrateBucketMsg := storageTypes.NewMsgMigrateBucket(c.MustGetDefaultAccount().GetAddress(), bucketName, opts.DstPrimarySPID) +// MigrateBucket - Get approval of migrating from SP, send the signed migrate bucket msg to greenfield chain and return the txn hash. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The name of the bucket to be migrated. +// +// - dstPrimarySPID: The sp id of the migration target SP. +// +// - opt: The options of send transaction of migration bucket +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when the request of getting approval or sending transaction failed, otherwise return nil. +func (c *Client) MigrateBucket(ctx context.Context, bucketName string, dstPrimarySPID uint32, opts types.MigrateBucketOptions) (string, error) { + migrateBucketMsg := storageTypes.NewMsgMigrateBucket(c.MustGetDefaultAccount().GetAddress(), bucketName, dstPrimarySPID) err := migrateBucketMsg.ValidateBasic() if err != nil { @@ -765,8 +954,20 @@ func (c *client) MigrateBucket(ctx context.Context, bucketName string, opts type return txnHash, nil } -// CancelMigrateBucket get approval of migrating bucket and send migrateBucket txn to greenfield chain, it returns the transaction hash value and error -func (c *client) CancelMigrateBucket(ctx context.Context, bucketName string, opts types.CancelMigrateBucketOptions) (uint64, string, error) { +// CancelMigrateBucket - Cancel migrate migration by sending the MsgCancelMigrateBucket msg. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The name of the migrating bucket to be canceled. +// +// - opt: The options of the proposal meta and transaction. +// +// - ret1: The proposal ID of canceling migration. +// +// - ret2: Transaction hash return from blockchain. +// +// - ret3: Return error when the request of cancel migration failed, otherwise return nil. +func (c *Client) CancelMigrateBucket(ctx context.Context, bucketName string, opts types.CancelMigrateBucketOptions) (uint64, string, error) { govModuleAddress, err := c.GetModuleAccountByName(ctx, govTypes.ModuleName) if err != nil { return 0, "", err @@ -780,11 +981,23 @@ func (c *client) CancelMigrateBucket(ctx context.Context, bucketName string, opt return 0, "", err } - return c.SubmitProposal(ctx, []sdk.Msg{cancelBucketMsg}, opts.ProposalDepositAmount, opts.ProposalTitle, opts.ProposalSummary, types.SubmitProposalOptions{Metadata: opts.ProposalMetaData, TxOption: opts.TxOpts}) + return c.SubmitProposal(ctx, []sdk.Msg{cancelBucketMsg}, opts.ProposalDepositAmount, opts.ProposalTitle, opts.ProposalSummary, types.SubmitProposalOptions{Metadata: opts.ProposalMetadata, TxOpts: opts.TxOpts}) } -// ListBucketsByPaymentAccount list bucket by payment account -func (c *client) ListBucketsByPaymentAccount(ctx context.Context, paymentAccount string, opts types.ListBucketsByPaymentAccountOptions) (types.ListBucketsByPaymentAccountResult, error) { +// ListBucketsByPaymentAccount - List bucket info by payment account. +// +// By inputting a collection of bucket IDs, we can retrieve the corresponding bucket data. If the bucket is nonexistent or has been deleted, a null value will be returned +// +// - ctx: Context variables for the current API call. +// +// - paymentAccount: Payment account defines the address of payment account. +// +// - opts: The options to set the meta to list buckets by payment account. +// +// - ret1: The result of bucket info under specific payment account. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) ListBucketsByPaymentAccount(ctx context.Context, paymentAccount string, opts types.ListBucketsByPaymentAccountOptions) (types.ListBucketsByPaymentAccountResult, error) { _, err := sdk.AccAddressFromHexUnsafe(paymentAccount) if err != nil { diff --git a/client/api_challenge.go b/client/api_challenge.go index de1edad1..ecb8099a 100644 --- a/client/api_challenge.go +++ b/client/api_challenge.go @@ -18,9 +18,8 @@ import ( types "github.com/bnb-chain/greenfield-go-sdk/types" ) -type Challenge interface { - // GetChallengeInfo return the challenge hash and data results based on the objectID and index info - // If the sp endpoint or sp address info is not set in the GetChallengeInfoOptions, the SP endpoint will be routed by the redundancyIndex +// IChallengeClient - Client APIs for operating and querying Greenfield challenges. +type IChallengeClient interface { GetChallengeInfo(ctx context.Context, objectID string, pieceIndex, redundancyIndex int, opts types.GetChallengeInfoOptions) (types.ChallengeResult, error) SubmitChallenge(ctx context.Context, challengerAddress, spOperatorAddress, bucketName, objectName string, randomIndex bool, segmentIndex uint32, txOption gnfdsdktypes.TxOption) (*sdk.TxResponse, error) AttestChallenge(ctx context.Context, submitterAddress, challengerAddress, spOperatorAddress string, challengeId uint64, objectId math.Uint, voteResult challengetypes.VoteResult, voteValidatorSet []uint64, VoteAggSignature []byte, txOption gnfdsdktypes.TxOption) (*sdk.TxResponse, error) @@ -29,9 +28,27 @@ type Challenge interface { ChallengeParams(ctx context.Context, req *challengetypes.QueryParamsRequest) (*challengetypes.QueryParamsResponse, error) } -// GetChallengeInfo sends request to challenge and get challenge result info -// The challenge info includes the piece data, piece hash roots and integrity hash corresponding to the accessed SP -func (c *client) GetChallengeInfo(ctx context.Context, objectID string, pieceIndex, redundancyIndex int, opts types.GetChallengeInfoOptions) (types.ChallengeResult, error) { +// GetChallengeInfo - Send request to storage provider, and get the integrity hash and data stored on the sp. +// +// This api is used for validators to judge whether a challenge valid or not. A validator's challenger account should be +// provided when constructing the client, otherwise the authorization will fail. +// +// - ctx: Context variables for the current API call. +// +// - objectID: The id of object being challenged. +// +// - pieceIndex: The index of the segment/piece of the object. +// +// - redundancyIndex: The redundancy index of the object, actually it also stands for which storage provider is being +// challenged and should response to this call - -1 stands for the primary storage provider. +// +// - opts: Options to define the storage provider address and its endpoint. If the storage provider address or endpoint +// is not set in the options, the storage provider endpoint will be routed by redundancyIndex. +// +// - ret1: The challenge info includes the piece data, piece hash roots and integrity hash corresponding to the accessed storage provider. +// +// - ret2: Return error when getting challenge info failed, otherwise return nil. +func (c *Client) GetChallengeInfo(ctx context.Context, objectID string, pieceIndex, redundancyIndex int, opts types.GetChallengeInfoOptions) (types.ChallengeResult, error) { if objectID == "" { return types.ChallengeResult{}, errors.New("fail to get objectId") } @@ -141,8 +158,31 @@ func (c *client) GetChallengeInfo(ctx context.Context, objectID string, pieceInd return result, nil } -// SubmitChallenge challenges the service provider data integrity, used by off-chain service greenfield-challenger. -func (c *client) SubmitChallenge(ctx context.Context, challengerAddress, spOperatorAddress, bucketName, objectName string, randomIndex bool, segmentIndex uint32, txOption gnfdsdktypes.TxOption) (*sdk.TxResponse, error) { +// SubmitChallenge - Challenge a storage provider's data integrity for a specific data object. +// +// User can submit a challenge when he/she find his/her data is lost or tampered. A successful challenge will punish +// the storage provider and reward the challenge submitter. +// +// - ctx: Context variables for the current API call. +// +// - challengerAddress: The address of the challenger, usually it's the address of current account. +// +// - spOperatorAddress: The operator address of the storage provider to be challenged. +// +// - bucketName: The bucket name of the object to be challenged. +// +// - objectName: The name of the object to be challenged. +// +// - randomIndex: Whether the segment/piece to be challenged will be randomly generated or not. +// +// - segmentIndex: The index of the segment/piece to be challenged. If randomIndex is true, then segmentIndex will be ignored. +// +// - txOption: The options for sending the tx. +// +// - ret1: The response of Greenfield transaction. +// +// - ret2: Return error when submitting challenge tx failed, otherwise return nil. +func (c *Client) SubmitChallenge(ctx context.Context, challengerAddress, spOperatorAddress, bucketName, objectName string, randomIndex bool, segmentIndex uint32, txOption gnfdsdktypes.TxOption) (*sdk.TxResponse, error) { challenger, err := sdk.AccAddressFromHexUnsafe(challengerAddress) if err != nil { return nil, err @@ -159,11 +199,36 @@ func (c *client) SubmitChallenge(ctx context.Context, challengerAddress, spOpera return resp.TxResponse, nil } -// Attest handles user's request for attesting a challenge. +// AttestChallenge - Send the attestation result of a challenge. +// +// In-turn validator can submit the attestation when enough votes are collected. // The attestation can include a valid challenge or is only for heartbeat purpose. -// If the challenge is valid, the related storage provider will be slashed. -// For heartbeat attestation, the challenge is invalid and the storage provider will not be slashed. -func (c *client) AttestChallenge(ctx context.Context, submitterAddress, challengerAddress, spOperatorAddress string, challengeId uint64, objectId math.Uint, +// If the challenge is valid, the related storage provider will be slashed, otherwise the storage provider will not be slashed. +// +// - ctx: Context variables for the current API call. +// +// - submitterAddress: The address of the attestation submitter, usually it's the address of current account. +// +// - challengerAddress: The address of the challenger. +// +// - spOperatorAddress: The operator address of the challenged storage provider. +// +// - challengeId: The id of the challenge to be attested. +// +// - objectId: The id of the object being challenged. +// +// - voteResult: The result of the off-chain votes from the majority validators. +// +// - voteValidatorSet: The bit set of validators who vote the voteResult for the challenge. +// +// - VoteAggSignature: The BLS aggregated signature for the attestation from validators. +// +// - txOption: The options for sending the tx. +// +// - ret1: The response of Greenfield transaction. +// +// - ret2: Return error when submitting attestation tx failed, otherwise return nil. +func (c *Client) AttestChallenge(ctx context.Context, submitterAddress, challengerAddress, spOperatorAddress string, challengeId uint64, objectId math.Uint, voteResult challengetypes.VoteResult, voteValidatorSet []uint64, VoteAggSignature []byte, txOption gnfdsdktypes.TxOption, ) (*sdk.TxResponse, error) { submitter, err := sdk.AccAddressFromHexUnsafe(submitterAddress) @@ -189,15 +254,45 @@ func (c *client) AttestChallenge(ctx context.Context, submitterAddress, challeng return resp.TxResponse, nil } -func (c *client) LatestAttestedChallenges(ctx context.Context, req *challengetypes.QueryLatestAttestedChallengesRequest) (*challengetypes.QueryLatestAttestedChallengesResponse, error) { +// LatestAttestedChallenges - Query the latest attested challenges (including heartbeat challenges). +// +// Greenfield will not keep the results of all challenges, only the latest ones will be kept and old ones will be pruned. +// +// - ctx: Context variables for the current API call. +// +// - req: The request to query latest attested challenges. +// +// - ret1: The latest attested challenges, including challenge id and attestation result. +// +// - ret2: Return error when getting latest attested challenges failed, otherwise return nil. +func (c *Client) LatestAttestedChallenges(ctx context.Context, req *challengetypes.QueryLatestAttestedChallengesRequest) (*challengetypes.QueryLatestAttestedChallengesResponse, error) { return c.chainClient.LatestAttestedChallenges(ctx, req) } -func (c *client) InturnAttestationSubmitter(ctx context.Context, req *challengetypes.QueryInturnAttestationSubmitterRequest) (*challengetypes.QueryInturnAttestationSubmitterResponse, error) { +// InturnAttestationSubmitter - Query the in-turn validator to submit challenge attestation. +// +// Greenfield will only allow the in-turn validator to submit challenge attestations. +// +// - ctx: Context variables for the current API call. +// +// - req: The request to query in-turn attestation submitter. +// +// - ret1: The in-turn validator information, including BLS pubkey of the validator and timeframe to submit attestations. +// +// - ret2: Return error when getting in-turn attestation submitter failed, otherwise return nil. +func (c *Client) InturnAttestationSubmitter(ctx context.Context, req *challengetypes.QueryInturnAttestationSubmitterRequest) (*challengetypes.QueryInturnAttestationSubmitterResponse, error) { return c.chainClient.InturnAttestationSubmitter(ctx, req) } -// ChallengeParams returns the on chain parameters for challenge module. -func (c *client) ChallengeParams(ctx context.Context, req *challengetypes.QueryParamsRequest) (*challengetypes.QueryParamsResponse, error) { +// ChallengeParams - Get challenge module's parameters of Greenfield blockchain. +// +// - ctx: Context variables for the current API call. +// +// - req: The request to query challenge parameters. +// +// - ret1: The parameters of challenge module. +// +// - ret2: Return error when getting parameters failed, otherwise return nil. +func (c *Client) ChallengeParams(ctx context.Context, req *challengetypes.QueryParamsRequest) (*challengetypes.QueryParamsResponse, error) { return c.chainClient.ChallengeQueryClient.Params(ctx, req) } diff --git a/client/api_client.go b/client/api_client.go index 2c85fbad..c8b29204 100644 --- a/client/api_client.go +++ b/client/api_client.go @@ -13,7 +13,6 @@ import ( "net/http" "net/http/httputil" "net/url" - "os" "strconv" "strings" "time" @@ -32,34 +31,30 @@ import ( "google.golang.org/grpc" ) -type Client interface { - Basic - Bucket - Object - Group - Challenge - Account - Payment - SP - Proposal - Validator - Distribution - CrossChain - FeeGrant - VirtualGroup - OffChainAuth - - GetDefaultAccount() (*types.Account, error) - SetDefaultAccount(account *types.Account) - EnableTrace(outputStream io.Writer, onlyTraceErr bool) +// IClient - Declare all Greenfield SDK Client APIs, including APIs for interacting with Greenfield Blockchain and SPs. +type IClient interface { + IBasicClient + IBucketClient + IObjectClient + IGroupClient + IChallengeClient + IAccountClient + IPaymentClient + ISPClient + IProposalClient + IValidatorClient + IDistributionClient + ICrossChainClient + IFeeGrantClient + IVirtualGroupClient + IAuthClient } -// client represents a Greenfield SDK client that can interact with the blockchain -// using the REST API, gRPC, or WebSocket endpoints. -type client struct { - // The chain client is used to interact with the blockchain +// Client - The implementation for IClient, implement all Client APIs for Greenfield SDK. +type Client struct { + // The chain Client is used to interact with the blockchain chainClient *sdkclient.GreenfieldClient - // The HTTP client is used to send HTTP requests to the greenfield blockchain and sp + // The HTTP Client is used to send HTTP requests to the greenfield blockchain and sp httpClient *http.Client // Service provider endpoints storageProviders map[uint32]*types.StorageProvider @@ -80,29 +75,33 @@ type client struct { expireSeconds uint64 } -// Option is a configuration struct used to provide optional parameters to the client constructor. +// Option - Configurations for providing optional parameters for the Greenfield SDK Client. type Option struct { // GrpcDialOption is the list of gRPC dial options used to configure the connection to the blockchain node. GrpcDialOption grpc.DialOption - // account used to set the default account of client + // DefaultAccount is the default account of Client. DefaultAccount *types.Account - // Secure is a flag that specifies whether the client should use HTTPS or not. + // Secure is a flag that specifies whether the Client should use HTTPS or not. Secure bool // Transport is the HTTP transport used to send requests to the storage provider endpoint. Transport http.RoundTripper - // Host is the target sp server hostname + // Host is the target sp server hostname. Host string // OffChainAuthOption consists of a EdDSA private key and the domain where the EdDSA keys will be registered for. + // // This property should not be set in most cases unless you want to use go-sdk to test if the SP support off-chain-auth feature. - // Once this property is set, the request will be signed in "off-chain-auth" way rather than v1 + // Once this property is set, the request will be signed in "GNFD1-EDDSA" way rather than GNFD1-ECDSA. OffChainAuthOption *OffChainAuthOption - // UseWebSocketConn specifies that connection to Chain is via websocket + // UseWebSocketConn specifies that connection to Chain is via websocket. UseWebSocketConn bool - // ExpireSeconds indicates the number of seconds after which the authentication of the request sent to the SP will become invalid,the default value is 1000 + // ExpireSeconds indicates the number of seconds after which the authentication of the request sent to the SP will become invalid,the default value is 1000. ExpireSeconds uint64 } -// OffChainAuthOption consists of a EdDSA private key and the domain where the EdDSA keys will be registered for. +// OffChainAuthOption - The optional configurations for off-chain-auth. +// +// The OffChainAuthOption consists of a EdDSA private key and the domain where the EdDSA keys will be registered for. +// // This auth mechanism is usually used in browser-based application. // That we support OffChainAuth configuration in go-sdk is to make the tests on off-chain-auth be convenient. type OffChainAuthOption struct { @@ -114,11 +113,20 @@ type OffChainAuthOption struct { ShouldRegisterPubKey bool } -// New - instantiate greenfield chain with chain info, account info and options. -// endpoint indicates the rpc address of greenfield -func New(chainID string, endpoint string, option Option) (Client, error) { +// New - New Greenfield Go SDK Client. +// +// - chainID: The Greenfield Blockchain's chainID that the Client would interact with. +// +// - endpoint: The Greenfield Blockchain's RPC URL that the Client would interact with. +// +// - option: The optional configurations for the Client. +// +// - ret1: The new client that created, in IClient format. +// +// - ret2: Return error when new Client failed, otherwise return nil. +func New(chainID string, endpoint string, option Option) (IClient, error) { if endpoint == "" || chainID == "" { - return nil, errors.New("fail to get grpcAddress and chainID to construct client") + return nil, errors.New("fail to get grpcAddress and chainID to construct Client") } var ( cc *sdkclient.GreenfieldClient @@ -140,7 +148,7 @@ func New(chainID string, endpoint string, option Option) (Client, error) { return nil, errors.New("the configured expire time exceeds max expire time") } - c := client{ + c := Client{ chainClient: cc, httpClient: &http.Client{Transport: option.Transport}, userAgent: types.UserAgent, @@ -178,19 +186,7 @@ func New(chainID string, endpoint string, option Option) (Client, error) { return &c, nil } -// EnableTrace support trace error info the request and the response -func (c *client) EnableTrace(output io.Writer, onlyTraceErr bool) { - if output == nil { - output = os.Stdout - } - - c.onlyTraceError = onlyTraceErr - - c.traceOutput = output - c.isTraceEnabled = true -} - -func (c *client) getSPUrlByBucket(bucketName string) (*url.URL, error) { +func (c *Client) getSPUrlByBucket(bucketName string) (*url.URL, error) { sp, err := c.pickStorageProviderByBucket(bucketName) if err != nil { return nil, err @@ -198,7 +194,7 @@ func (c *client) getSPUrlByBucket(bucketName string) (*url.URL, error) { return sp.EndPoint, nil } -func (c *client) pickStorageProviderByBucket(bucketName string) (*types.StorageProvider, error) { +func (c *Client) pickStorageProviderByBucket(bucketName string) (*types.StorageProvider, error) { ctx := context.Background() bucketInfo, err := c.HeadBucket(ctx, bucketName) if err != nil { @@ -228,7 +224,7 @@ func (c *client) pickStorageProviderByBucket(bucketName string) (*types.StorageP } // getSPUrlByID route url of the sp from sp id -func (c *client) getSPUrlByID(id uint32) (*url.URL, error) { +func (c *Client) getSPUrlByID(id uint32) (*url.URL, error) { sp, ok := c.storageProviders[id] if ok { return sp.EndPoint, nil @@ -238,7 +234,7 @@ func (c *client) getSPUrlByID(id uint32) (*url.URL, error) { } // getSPUrlByAddr route url of the sp from sp address -func (c *client) getSPUrlByAddr(address string) (*url.URL, error) { +func (c *Client) getSPUrlByAddr(address string) (*url.URL, error) { acc, err := sdk.AccAddressFromHexUnsafe(address) if err != nil { return nil, err @@ -253,7 +249,7 @@ func (c *client) getSPUrlByAddr(address string) (*url.URL, error) { } // getInServiceSP return the first SP endpoint which is in service in SP list -func (c *client) getInServiceSP() (*url.URL, error) { +func (c *Client) getInServiceSP() (*url.URL, error) { ctx := context.Background() spList, err := c.ListStorageProviders(ctx, true) if err != nil { @@ -315,7 +311,7 @@ func DefaultDownloadSegmentHook(seg int64) error { } // newRequest constructs the http request, set url, body and headers -func (c *client) newRequest(ctx context.Context, method string, meta requestMeta, +func (c *Client) newRequest(ctx context.Context, method string, meta requestMeta, body interface{}, txnHash string, isAdminAPi bool, endpoint *url.URL, ) (req *http.Request, err error) { isVirtualHost := c.isVirtualHostStyleUrl(*endpoint, meta.bucketName) @@ -445,8 +441,8 @@ func (c *client) newRequest(ctx context.Context, method string, meta requestMeta return } -// doAPI call client.Do() to send request and read response from servers -func (c *client) doAPI(ctx context.Context, req *http.Request, meta requestMeta, closeBody bool) (*http.Response, error) { +// doAPI call Client.Do() to send request and read response from servers +func (c *Client) doAPI(ctx context.Context, req *http.Request, meta requestMeta, closeBody bool) (*http.Response, error) { var cancel context.CancelFunc if closeBody { ctx, cancel = context.WithCancel(ctx) @@ -502,7 +498,7 @@ func (c *client) doAPI(ctx context.Context, req *http.Request, meta requestMeta, } // sendReq sends the message via REST and handles the response -func (c *client) sendReq(ctx context.Context, metadata requestMeta, opt *sendOptions, endpoint *url.URL) (res *http.Response, err error) { +func (c *Client) sendReq(ctx context.Context, metadata requestMeta, opt *sendOptions, endpoint *url.URL) (res *http.Response, err error) { req, err := c.newRequest(ctx, opt.method, metadata, opt.body, opt.txnHash, opt.isAdminApi, endpoint) if err != nil { return nil, err @@ -516,7 +512,7 @@ func (c *client) sendReq(ctx context.Context, metadata requestMeta, opt *sendOpt return resp, nil } -func (c *client) SplitPartInfo(objectSize int64, configuredPartSize uint64) (totalPartsCount int, partSize int64, lastPartSize int64, err error) { +func (c *Client) SplitPartInfo(objectSize int64, configuredPartSize uint64) (totalPartsCount int, partSize int64, lastPartSize int64, err error) { partSizeFlt := float64(configuredPartSize) // Total parts count. totalPartsCount = int(math.Ceil(float64(objectSize) / partSizeFlt)) @@ -528,7 +524,7 @@ func (c *client) SplitPartInfo(objectSize int64, configuredPartSize uint64) (tot } // generateURL constructs the target request url based on the parameters -func (c *client) generateURL(bucketName string, objectName string, relativePath string, +func (c *Client) generateURL(bucketName string, objectName string, relativePath string, queryValues url.Values, isAdminApi bool, endpoint *url.URL, isVirtualHost bool, ) (*url.URL, error) { host := endpoint.Host @@ -581,7 +577,7 @@ func (c *client) generateURL(bucketName string, objectName string, relativePath } // signRequest signs the request and set authorization before send to server -func (c *client) signRequest(req *http.Request) error { +func (c *Client) signRequest(req *http.Request) error { // use offChainAuth if OffChainAuthOption is set if c.offChainAuthOption != nil { req.Header.Set("X-Gnfd-User-Address", c.defaultAccount.GetAddress().String()) @@ -613,7 +609,7 @@ func (c *client) signRequest(req *http.Request) error { } // returns true if virtual hosted style requests are to be used. -func (c *client) isVirtualHostStyleUrl(url url.URL, bucketName string) bool { +func (c *Client) isVirtualHostStyleUrl(url url.URL, bucketName string) bool { if bucketName == "" { return false } @@ -629,7 +625,7 @@ func (c *client) isVirtualHostStyleUrl(url url.URL, bucketName string) bool { return true } -func (c *client) dumpSPMsg(req *http.Request, resp *http.Response) { +func (c *Client) dumpSPMsg(req *http.Request, resp *http.Response) { var err error defer func() { if err != nil { @@ -683,7 +679,7 @@ func (c *client) dumpSPMsg(req *http.Request, resp *http.Response) { // GetPieceHashRoots returns primary pieces, secondary piece Hash roots list and the object size // It is used for generate meta of object on the chain -func (c *client) GetPieceHashRoots(reader io.Reader, segSize int64, +func (c *Client) GetPieceHashRoots(reader io.Reader, segSize int64, dataShards, parityShards int, ) ([]byte, [][]byte, int64, storageTypes.RedundancyType, error) { pieceHashRoots, size, redundancyType, err := hashlib.ComputeIntegrityHash(reader, segSize, dataShards, parityShards, false) @@ -695,7 +691,7 @@ func (c *client) GetPieceHashRoots(reader io.Reader, segSize int64, } // sendPutPolicyTxn broadcast the putPolicy msg and return the txn hash -func (c *client) sendPutPolicyTxn(ctx context.Context, msg *storageTypes.MsgPutPolicy, txOpts *gnfdSdkTypes.TxOption) (string, error) { +func (c *Client) sendPutPolicyTxn(ctx context.Context, msg *storageTypes.MsgPutPolicy, txOpts *gnfdSdkTypes.TxOption) (string, error) { if err := msg.ValidateBasic(); err != nil { return "", err } @@ -709,7 +705,7 @@ func (c *client) sendPutPolicyTxn(ctx context.Context, msg *storageTypes.MsgPutP } // sendDelPolicyTxn broadcast the deletePolicy msg and return the txn hash -func (c *client) sendDelPolicyTxn(ctx context.Context, operator sdk.AccAddress, resource string, principal *permTypes.Principal, txOpts *gnfdSdkTypes.TxOption) (string, error) { +func (c *Client) sendDelPolicyTxn(ctx context.Context, operator sdk.AccAddress, resource string, principal *permTypes.Principal, txOpts *gnfdSdkTypes.TxOption) (string, error) { delPolicyMsg := storageTypes.NewMsgDeletePolicy(operator, resource, principal) if err := delPolicyMsg.ValidateBasic(); err != nil { @@ -724,7 +720,7 @@ func (c *client) sendDelPolicyTxn(ctx context.Context, operator sdk.AccAddress, return resp.TxResponse.TxHash, err } -func (c *client) sendTxn(ctx context.Context, msg sdk.Msg, opt *gnfdSdkTypes.TxOption) (string, error) { +func (c *Client) sendTxn(ctx context.Context, msg sdk.Msg, opt *gnfdSdkTypes.TxOption) (string, error) { if err := msg.ValidateBasic(); err != nil { return "", err } @@ -736,29 +732,8 @@ func (c *client) sendTxn(ctx context.Context, msg sdk.Msg, opt *gnfdSdkTypes.TxO return resp.TxResponse.TxHash, err } -// GetDefaultAccount returns the account address of default account in client -func (c *client) GetDefaultAccount() (*types.Account, error) { - if c.MustGetDefaultAccount() == nil { - return nil, types.ErrorDefaultAccountNotExist - } - return c.MustGetDefaultAccount(), nil -} - -// SetDefaultAccount will set the default account -func (c *client) SetDefaultAccount(account *types.Account) { - c.defaultAccount = account - c.chainClient.SetKeyManager(account.GetKeyManager()) -} - -func (c *client) MustGetDefaultAccount() *types.Account { - if c.defaultAccount == nil { - panic("Default account not exist, Use SetDefaultAccount to set ") - } - return c.defaultAccount -} - // getEndpointByOpt return the SP endpoint by listOptions -func (c *client) getEndpointByOpt(opts *types.EndPointOptions) (*url.URL, error) { +func (c *Client) getEndpointByOpt(opts *types.EndPointOptions) (*url.URL, error) { var ( endpoint *url.URL useHttps bool diff --git a/client/api_crosschain.go b/client/api_crosschain.go index 55077a0d..30e26410 100644 --- a/client/api_crosschain.go +++ b/client/api_crosschain.go @@ -13,7 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -type CrossChain interface { +type ICrossChainClient interface { TransferOut(ctx context.Context, toAddress string, amount math.Int, txOption gnfdSdkTypes.TxOption) (*sdk.TxResponse, error) Claims(ctx context.Context, srcShainId, destChainId uint32, sequence uint64, timestamp uint64, payload []byte, voteAddrSet []uint64, aggSignature []byte, txOption gnfdSdkTypes.TxOption) (*sdk.TxResponse, error) @@ -27,8 +27,20 @@ type CrossChain interface { MirrorObject(ctx context.Context, destChainId sdk.ChainID, objectId math.Uint, bucketName, objectName string, txOption gnfdSdkTypes.TxOption) (*sdk.TxResponse, error) } -// TransferOut makes a transfer from Greenfield to BSC -func (c *client) TransferOut(ctx context.Context, toAddress string, amount math.Int, txOption gnfdSdkTypes.TxOption) (*sdk.TxResponse, error) { +// TransferOut - Make a transfer from Greenfield to BSC +// +// - ctx: Context variables for the current API call. +// +// - toAddress: The destination address in BSC. +// +// - amount: The amount of BNB to transfer. +// +// - txOption: The txOption for sending transactions. +// +// - ret1: Transaction response from Greenfield. +// +// - ret2: Return error if transaction failed, otherwise return nil. +func (c *Client) TransferOut(ctx context.Context, toAddress string, amount math.Int, txOption gnfdSdkTypes.TxOption) (*sdk.TxResponse, error) { msgTransferOut := bridgetypes.NewMsgTransferOut(c.MustGetDefaultAccount().GetAddress().String(), toAddress, &sdk.Coin{Denom: gnfdSdkTypes.Denom, Amount: amount}, @@ -40,13 +52,35 @@ func (c *client) TransferOut(ctx context.Context, toAddress string, amount math. return txResp.TxResponse, nil } -// Claims cross-chain packages from BSC to Greenfield, used by relayers which run by validators -func (c *client) Claims(ctx context.Context, srcShainId, destChainId uint32, sequence uint64, +// Claims - Claim cross-chain packages from BSC to Greenfield, used by relayers which run by validators +// +// - ctx: Context variables for the current API call. +// +// - srcChainId: The source chain id. +// +// - destChainId: The destination chain id. +// +// - sequence: The sequence of the claim. +// +// - timestamp: The timestamp of the cross-chain packages. +// +// - payload: The payload of the claim. +// +// - voteAddrSet: The bitset of the voted validators. +// +// - aggSignature: The aggregated bls signature of the claim. +// +// - txOption: The txOption for sending transactions. +// +// - ret1: Transaction response from Greenfield. +// +// - ret2: Return error if transaction failed, otherwise return nil. +func (c *Client) Claims(ctx context.Context, srcChainId, destChainId uint32, sequence uint64, timestamp uint64, payload []byte, voteAddrSet []uint64, aggSignature []byte, txOption gnfdSdkTypes.TxOption, ) (*sdk.TxResponse, error) { msg := oracletypes.NewMsgClaim( c.MustGetDefaultAccount().GetAddress().String(), - srcShainId, + srcChainId, destChainId, sequence, timestamp, @@ -61,8 +95,18 @@ func (c *client) Claims(ctx context.Context, srcShainId, destChainId uint32, seq return txResp.TxResponse, nil } -// GetChannelSendSequence gets the next send sequence for a channel -func (c *client) GetChannelSendSequence(ctx context.Context, destChainId sdk.ChainID, channelId uint32) (uint64, error) { +// GetChannelSendSequence - Get the next send sequence for a channel +// +// - ctx: Context variables for the current API call. +// +// - destChainId: The destination chain id. +// +// - channelId: The channel id to query. +// +// - ret1: Send sequence of the channel. +// +// - ret2: Return error if the query failed, otherwise return nil. +func (c *Client) GetChannelSendSequence(ctx context.Context, destChainId sdk.ChainID, channelId uint32) (uint64, error) { resp, err := c.chainClient.CrosschainQueryClient.SendSequence( ctx, &crosschaintypes.QuerySendSequenceRequest{ @@ -76,8 +120,18 @@ func (c *client) GetChannelSendSequence(ctx context.Context, destChainId sdk.Cha return resp.Sequence, nil } -// GetChannelReceiveSequence gets the next receive sequence for a channel -func (c *client) GetChannelReceiveSequence(ctx context.Context, destChainId sdk.ChainID, channelId uint32) (uint64, error) { +// GetChannelReceiveSequence - Get the next receive sequence for a channel +// +// - ctx: Context variables for the current API call. +// +// - destChainId: The destination chain id. +// +// - channelId: The channel id to query. +// +// - ret1: Send sequence of the channel. +// +// - ret2: Return error if the query failed, otherwise return nil. +func (c *Client) GetChannelReceiveSequence(ctx context.Context, destChainId sdk.ChainID, channelId uint32) (uint64, error) { resp, err := c.chainClient.CrosschainQueryClient.ReceiveSequence( ctx, &crosschaintypes.QueryReceiveSequenceRequest{ @@ -91,12 +145,33 @@ func (c *client) GetChannelReceiveSequence(ctx context.Context, destChainId sdk. return resp.Sequence, nil } -// GetInturnRelayer gets the in-turn relayer bls public key and its relay interval -func (c *client) GetInturnRelayer(ctx context.Context, req *oracletypes.QueryInturnRelayerRequest) (*oracletypes.QueryInturnRelayerResponse, error) { +// GetInturnRelayer - Get the in-turn relayer bls public key and its relay interval +// +// - ctx: Context variables for the current API call. +// +// - req: The request to query in-turn relayer. +// +// - ret1: The response of the `QueryInturnRelayerRequest` query. +// +// - ret2: Return error if the query failed, otherwise return nil. +func (c *Client) GetInturnRelayer(ctx context.Context, req *oracletypes.QueryInturnRelayerRequest) (*oracletypes.QueryInturnRelayerResponse, error) { return c.chainClient.InturnRelayer(ctx, req) } -func (c *client) GetCrossChainPackage(ctx context.Context, destChainId sdk.ChainID, channelId uint32, sequence uint64) ([]byte, error) { +// GetCrossChainPackage - Get the cross-chain package by sequence. +// +// - ctx: Context variables for the current API call. +// +// - destChainId: The destination chain id. +// +// - channelId: The channel id to query. +// +// - sequence: The sequence of the cross-chain package. +// +// - ret1: The bytes of the cross-chain package. +// +// - ret2: Return error if the query failed, otherwise return nil. +func (c *Client) GetCrossChainPackage(ctx context.Context, destChainId sdk.ChainID, channelId uint32, sequence uint64) ([]byte, error) { resp, err := c.chainClient.CrossChainPackage( ctx, &crosschaintypes.QueryCrossChainPackageRequest{ @@ -111,8 +186,22 @@ func (c *client) GetCrossChainPackage(ctx context.Context, destChainId sdk.Chain return resp.Package, nil } -// MirrorGroup mirrors the group to BSC as NFT -func (c *client) MirrorGroup(ctx context.Context, destChainId sdk.ChainID, groupId math.Uint, groupName string, txOption gnfdSdkTypes.TxOption) (*sdk.TxResponse, error) { +// MirrorGroup - Mirror the group to BSC as an NFT +// +// - ctx: Context variables for the current API call. +// +// - destChainId: The destination chain id. +// +// - groupId: The group id to mirror. +// +// - groupName: The group name. +// +// - txOption: The txOption for sending transactions. +// +// - ret1: Transaction response from Greenfield. +// +// - ret2: Return error if the transaction failed, otherwise return nil. +func (c *Client) MirrorGroup(ctx context.Context, destChainId sdk.ChainID, groupId math.Uint, groupName string, txOption gnfdSdkTypes.TxOption) (*sdk.TxResponse, error) { msgMirrorGroup := storagetypes.NewMsgMirrorGroup(c.MustGetDefaultAccount().GetAddress(), destChainId, groupId, groupName) txResp, err := c.BroadcastTx(ctx, []sdk.Msg{msgMirrorGroup}, &txOption) if err != nil { @@ -121,8 +210,22 @@ func (c *client) MirrorGroup(ctx context.Context, destChainId sdk.ChainID, group return txResp.TxResponse, nil } -// MirrorBucket mirrors the bucket to BSC as NFT -func (c *client) MirrorBucket(ctx context.Context, destChainId sdk.ChainID, bucketId math.Uint, bucketName string, txOption gnfdSdkTypes.TxOption) (*sdk.TxResponse, error) { +// MirrorBucket - Mirror the bucket to BSC as an NFT +// +// - ctx: Context variables for the current API call. +// +// - destChainId: The destination chain id. +// +// - bucketId: The bucket id to mirror. +// +// - bucketName: The bucket name. +// +// - txOption: The txOption for sending transactions. +// +// - ret1: Transaction response from Greenfield. +// +// - ret2: Return error if the transaction failed, otherwise return nil. +func (c *Client) MirrorBucket(ctx context.Context, destChainId sdk.ChainID, bucketId math.Uint, bucketName string, txOption gnfdSdkTypes.TxOption) (*sdk.TxResponse, error) { msgMirrorBucket := storagetypes.NewMsgMirrorBucket(c.MustGetDefaultAccount().GetAddress(), destChainId, bucketId, bucketName) txResp, err := c.BroadcastTx(ctx, []sdk.Msg{msgMirrorBucket}, &txOption) if err != nil { @@ -131,8 +234,24 @@ func (c *client) MirrorBucket(ctx context.Context, destChainId sdk.ChainID, buck return txResp.TxResponse, nil } -// MirrorObject mirrors the object to BSC as NFT -func (c *client) MirrorObject(ctx context.Context, destChainId sdk.ChainID, objectId math.Uint, bucketName, objectName string, txOption gnfdSdkTypes.TxOption) (*sdk.TxResponse, error) { +// MirrorObject - Mirror the object to BSC as an NFT +// +// - ctx: Context variables for the current API call. +// +// - destChainId: The destination chain id. +// +// - objectId: The object id to mirror. +// +// - bucketName: The bucket name. +// +// - objectName: The object name. +// +// - txOption: The txOption for sending transactions. +// +// - ret1: Transaction response from Greenfield. +// +// - ret2: Return error if the transaction failed, otherwise return nil. +func (c *Client) MirrorObject(ctx context.Context, destChainId sdk.ChainID, objectId math.Uint, bucketName, objectName string, txOption gnfdSdkTypes.TxOption) (*sdk.TxResponse, error) { msgMirrorObject := storagetypes.NewMsgMirrorObject(c.MustGetDefaultAccount().GetAddress(), destChainId, objectId, bucketName, objectName) txResp, err := c.BroadcastTx(ctx, []sdk.Msg{msgMirrorObject}, &txOption) if err != nil { diff --git a/client/api_distribution.go b/client/api_distribution.go index 3b67959a..4992221d 100644 --- a/client/api_distribution.go +++ b/client/api_distribution.go @@ -9,15 +9,25 @@ import ( distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" ) -type Distribution interface { +type IDistributionClient interface { SetWithdrawAddress(ctx context.Context, withdrawAddr string, txOption gnfdsdktypes.TxOption) (string, error) WithdrawValidatorCommission(ctx context.Context, txOption gnfdsdktypes.TxOption) (string, error) WithdrawDelegatorReward(ctx context.Context, validatorAddr string, txOption gnfdsdktypes.TxOption) (string, error) FundCommunityPool(ctx context.Context, amount math.Int, txOption gnfdsdktypes.TxOption) (string, error) } -// SetWithdrawAddress sets the withdrawal address for a delegator (or validator self-delegation). -func (c *client) SetWithdrawAddress(ctx context.Context, withdrawAddr string, txOption gnfdsdktypes.TxOption) (string, error) { +// SetWithdrawAddress - Set the withdrawal address for a delegator (or validator self-delegation). +// +// - ctx: Context variables for the current API call. +// +// - withdrawAddr: The withdrawal address to set. +// +// - txOption: The txOption for sending transactions. +// +// - ret1: Transaction hash of the transaction. +// +// - ret2: Return error if the transaction failed, otherwise return nil. +func (c *Client) SetWithdrawAddress(ctx context.Context, withdrawAddr string, txOption gnfdsdktypes.TxOption) (string, error) { withdraw, err := sdk.AccAddressFromHexUnsafe(withdrawAddr) if err != nil { return "", err @@ -30,8 +40,16 @@ func (c *client) SetWithdrawAddress(ctx context.Context, withdrawAddr string, tx return resp.TxResponse.TxHash, nil } -// WithdrawValidatorCommission withdraw accumulated commission by validator -func (c *client) WithdrawValidatorCommission(ctx context.Context, txOption gnfdsdktypes.TxOption) (string, error) { +// WithdrawValidatorCommission - Withdraw accumulated commission by validator. +// +// - ctx: Context variables for the current API call. +// +// - txOption: The txOption for sending transactions. +// +// - ret1: Transaction hash of the transaction. +// +// - ret2: Return error if the transaction failed, otherwise return nil. +func (c *Client) WithdrawValidatorCommission(ctx context.Context, txOption gnfdsdktypes.TxOption) (string, error) { msg := distrtypes.NewMsgWithdrawValidatorCommission(c.MustGetDefaultAccount().GetAddress()) resp, err := c.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) if err != nil { @@ -40,8 +58,18 @@ func (c *client) WithdrawValidatorCommission(ctx context.Context, txOption gnfds return resp.TxResponse.TxHash, nil } -// WithdrawDelegatorReward withdraw rewards by a delegator -func (c *client) WithdrawDelegatorReward(ctx context.Context, validatorAddr string, txOption gnfdsdktypes.TxOption) (string, error) { +// WithdrawDelegatorReward - Withdraw rewards by a delegator. +// +// - ctx: Context variables for the current API call. +// +// - validatorAddr: The validator address to withdraw from. +// +// - txOption: The txOption for sending transactions. +// +// - ret1: Transaction hash of the transaction. +// +// - ret2: Return error if the transaction failed, otherwise return nil. +func (c *Client) WithdrawDelegatorReward(ctx context.Context, validatorAddr string, txOption gnfdsdktypes.TxOption) (string, error) { validator, err := sdk.AccAddressFromHexUnsafe(validatorAddr) if err != nil { return "", err @@ -54,8 +82,18 @@ func (c *client) WithdrawDelegatorReward(ctx context.Context, validatorAddr stri return resp.TxResponse.TxHash, nil } -// FundCommunityPool sends coins directly from the sender to the community pool. -func (c *client) FundCommunityPool(ctx context.Context, amount math.Int, txOption gnfdsdktypes.TxOption) (string, error) { +// FundCommunityPool - Sends coins directly from the sender to the community pool. +// +// - ctx: Context variables for the current API call. +// +// - amount: The amount of BNB to send. +// +// - txOption: The txOption for sending transactions. +// +// - ret1: Transaction hash of the transaction. +// +// - ret2: Return error if the transaction failed, otherwise return nil. +func (c *Client) FundCommunityPool(ctx context.Context, amount math.Int, txOption gnfdsdktypes.TxOption) (string, error) { msg := distrtypes.NewMsgFundCommunityPool(sdk.Coins{sdk.Coin{Denom: gnfdsdktypes.Denom, Amount: amount}}, c.MustGetDefaultAccount().GetAddress()) resp, err := c.BroadcastTx(ctx, []sdk.Msg{msg}, &txOption) if err != nil { diff --git a/client/api_feegrant.go b/client/api_feegrant.go index ed89ace4..f9a94c6c 100644 --- a/client/api_feegrant.go +++ b/client/api_feegrant.go @@ -10,7 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/feegrant" ) -type FeeGrant interface { +type IFeeGrantClient interface { GrantBasicAllowance(ctx context.Context, granteeAddr string, feeAllowanceAmount math.Int, expiration *time.Time, txOption gnfdsdktypes.TxOption) (string, error) QueryBasicAllowance(ctx context.Context, granterAddr, granteeAddr string) (*feegrant.BasicAllowance, error) @@ -23,7 +23,7 @@ type FeeGrant interface { } // GrantBasicAllowance grants the grantee the BasicAllowance with specified amount and expiration. -func (c *client) GrantBasicAllowance(ctx context.Context, granteeAddr string, feeAllowanceAmount math.Int, expiration *time.Time, txOption gnfdsdktypes.TxOption) (string, error) { +func (c *Client) GrantBasicAllowance(ctx context.Context, granteeAddr string, feeAllowanceAmount math.Int, expiration *time.Time, txOption gnfdsdktypes.TxOption) (string, error) { grantee, err := sdk.AccAddressFromHexUnsafe(granteeAddr) if err != nil { return "", err @@ -45,7 +45,7 @@ func (c *client) GrantBasicAllowance(ctx context.Context, granteeAddr string, fe } // GrantAllowance provides a generic way to grant different types of allowance(BasicAllowance, PeriodicAllowance, AllowedMsgAllowance), the user needs to construct the desired type of allowance -func (c *client) GrantAllowance(ctx context.Context, granteeAddr string, allowance feegrant.FeeAllowanceI, txOption gnfdsdktypes.TxOption) (string, error) { +func (c *Client) GrantAllowance(ctx context.Context, granteeAddr string, allowance feegrant.FeeAllowanceI, txOption gnfdsdktypes.TxOption) (string, error) { grantee, err := sdk.AccAddressFromHexUnsafe(granteeAddr) if err != nil { return "", err @@ -62,7 +62,7 @@ func (c *client) GrantAllowance(ctx context.Context, granteeAddr string, allowan } // RevokeAllowance revokes allowance on a grantee by the granter -func (c *client) RevokeAllowance(ctx context.Context, granteeAddr string, txOption gnfdsdktypes.TxOption) (string, error) { +func (c *Client) RevokeAllowance(ctx context.Context, granteeAddr string, txOption gnfdsdktypes.TxOption) (string, error) { grantee, err := sdk.AccAddressFromHexUnsafe(granteeAddr) if err != nil { return "", err @@ -79,7 +79,7 @@ func (c *client) RevokeAllowance(ctx context.Context, granteeAddr string, txOpti } // QueryBasicAllowance queries the BasicAllowance -func (c *client) QueryBasicAllowance(ctx context.Context, granterAddr, granteeAddr string) (*feegrant.BasicAllowance, error) { +func (c *Client) QueryBasicAllowance(ctx context.Context, granterAddr, granteeAddr string) (*feegrant.BasicAllowance, error) { allowance, err := c.QueryAllowance(ctx, granterAddr, granteeAddr) if err != nil { return nil, err @@ -91,7 +91,7 @@ func (c *client) QueryBasicAllowance(ctx context.Context, granterAddr, granteeAd return basicAllowance, nil } -func (c *client) QueryAllowance(ctx context.Context, granterAddr, granteeAddr string) (*feegrant.Grant, error) { +func (c *Client) QueryAllowance(ctx context.Context, granterAddr, granteeAddr string) (*feegrant.Grant, error) { _, err := sdk.AccAddressFromHexUnsafe(granterAddr) if err != nil { return nil, err @@ -111,7 +111,7 @@ func (c *client) QueryAllowance(ctx context.Context, granterAddr, granteeAddr st return response.Allowance, nil } -func (c *client) QueryAllowances(ctx context.Context, granteeAddr string) ([]*feegrant.Grant, error) { +func (c *Client) QueryAllowances(ctx context.Context, granteeAddr string) ([]*feegrant.Grant, error) { _, err := sdk.AccAddressFromHexUnsafe(granteeAddr) if err != nil { return nil, err @@ -126,7 +126,7 @@ func (c *client) QueryAllowances(ctx context.Context, granteeAddr string) ([]*fe return response.Allowances, nil } -func (c *client) QueryGranterAllowances(ctx context.Context, granterAddr string) ([]*feegrant.Grant, error) { +func (c *Client) QueryGranterAllowances(ctx context.Context, granterAddr string) ([]*feegrant.Grant, error) { _, err := sdk.AccAddressFromHexUnsafe(granterAddr) if err != nil { return nil, err diff --git a/client/api_group.go b/client/api_group.go index 06ec7c82..dae2d3e7 100644 --- a/client/api_group.go +++ b/client/api_group.go @@ -23,74 +23,96 @@ import ( "github.com/bnb-chain/greenfield-go-sdk/pkg/utils" ) -type Group interface { - // CreateGroup create a new group on greenfield chain the group members can be initialized or not +// IGroupClient interface defines functions related to Group. +type IGroupClient interface { CreateGroup(ctx context.Context, groupName string, opt types.CreateGroupOptions) (string, error) - // DeleteGroup send DeleteGroup txn to greenfield chain and return txn hash DeleteGroup(ctx context.Context, groupName string, opt types.DeleteGroupOption) (string, error) - // UpdateGroupMember support adding or removing members from the group and return the txn hash - // groupOwnerAddr indicates the HEX-encoded string of the group owner address - // addAddresses indicates the HEX-encoded string list of the member addresses to be added - // removeAddresses indicates the HEX-encoded string list of the member addresses to be removed - // expirationTime indicates the expiration time of the group member, user need set the expiration time for the addAddresses UpdateGroupMember(ctx context.Context, groupName string, groupOwnerAddr string, addAddresses, removeAddresses []string, opts types.UpdateGroupMemberOption) (string, error) - // LeaveGroup make the member leave the specific group - // groupOwnerAddr indicates the HEX-encoded string of the group owner address LeaveGroup(ctx context.Context, groupName string, groupOwnerAddr string, opt types.LeaveGroupOption) (string, error) - // HeadGroup query the groupInfo on chain, return the group info if exists return err info if group not exist - // groupOwnerAddr indicates the HEX-encoded string of the group owner address HeadGroup(ctx context.Context, groupName string, groupOwnerAddr string) (*storageTypes.GroupInfo, error) - // HeadGroupMember query the group member info on chain, return true if the member exists in group - // groupOwnerAddr indicates the HEX-encoded string of the group owner address - // headMember indicates the HEX-encoded string of the group member address HeadGroupMember(ctx context.Context, groupName string, groupOwner, headMember string) bool - // PutGroupPolicy apply group policy to user specified by principalAddr, the sender need to be the owner of the group - // principalAddr indicates the HEX-encoded string of the principal address PutGroupPolicy(ctx context.Context, groupName string, principalAddr string, statements []*permTypes.Statement, opt types.PutPolicyOption) (string, error) - // DeleteGroupPolicy delete group policy of the principal, the sender need to be the owner of the group - // principalAddr indicates the HEX-encoded string of the principal address DeleteGroupPolicy(ctx context.Context, groupName string, principalAddr string, opt types.DeletePolicyOption) (string, error) - // GetBucketPolicyOfGroup get the bucket policy info of the group specified by group id - // it queries a bucket policy that grants permission to a group GetBucketPolicyOfGroup(ctx context.Context, bucketName string, groupId uint64) (*permTypes.Policy, error) - // GetObjectPolicyOfGroup get the object policy info of the group specified by group id - // it queries an object policy that grants permission to a group GetObjectPolicyOfGroup(ctx context.Context, bucketName, objectName string, groupId uint64) (*permTypes.Policy, error) - // GetGroupPolicy get the group policy info of the user specified by principalAddr GetGroupPolicy(ctx context.Context, groupName string, principalAddr string) (*permTypes.Policy, error) - // ListGroup get the group list by name and prefix. - // prefix is the start of the search pattern. The system will only return groups that start with this prefix. - // name is the ending of the search pattern. - // it providers fuzzy searches by inputting a specific name and prefix ListGroup(ctx context.Context, name, prefix string, opts types.ListGroupsOptions) (types.ListGroupsResult, error) - // RenewGroupMember renew a list of group members and their expiration time RenewGroupMember(ctx context.Context, groupOwnerAddr, groupName string, memberAddresses []string, opts types.RenewGroupMemberOption) (string, error) - // ListGroupMembers returns a list of members contained within the group specified by the group id, including those for which the user's expiration time has already elapsed ListGroupMembers(ctx context.Context, groupID int64, opts types.GroupMembersPaginationOptions) (*types.GroupMembersResult, error) - // ListGroupsByAccount returns a list of all groups that the user has joined, including those for which the user's expiration time has already elapsed - // By default, the user is the sender. Other users can be set using the option ListGroupsByAccount(ctx context.Context, opts types.GroupsPaginationOptions) (*types.GroupsResult, error) - // ListGroupsByOwner returns a list of groups owned by the specified user, including those for which the user's expiration time has already elapsed - // By default, the user is the sender. Other users can be set using the option ListGroupsByOwner(ctx context.Context, opts types.GroupsOwnerPaginationOptions) (*types.GroupsResult, error) ListGroupsByGroupID(ctx context.Context, groupIDs []uint64, opts types.EndPointOptions) (types.ListGroupsByGroupIDResponse, error) } -// CreateGroup create a new group on greenfield chain, the group members can be initialized or not -func (c *client) CreateGroup(ctx context.Context, groupName string, opt types.CreateGroupOptions) (string, error) { +// CreateGroup - Create a new group without group members on Greenfield blockchain, and group members can be added by UpdateGroupMember transaction. +// +// A `Group` is a collection of accounts that share the same permissions, allowing them to be handled as a single entity. +// +// Examples of permissions include: +// +// Put, List, Get, Delete, Copy, and Execute data objects; +// Create, Delete, and List buckets +// Create, Delete, ListMembers, Leave groups +// Create, Associate payment accounts +// Grant, Revoke the above permissions +// +// # For more details regarding `Group`, please refer to https://docs.bnbchain.org/greenfield-docs/docs/guide/greenfield-blockchain/modules/permission +// +// - ctx: Context variables for the current API call. +// +// - groupName: The group name identifies the group. +// +// - opt: The options for customizing a group and transaction. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret3: Return error when the request failed, otherwise return nil. +func (c *Client) CreateGroup(ctx context.Context, groupName string, opt types.CreateGroupOptions) (string, error) { createGroupMsg := storageTypes.NewMsgCreateGroup(c.MustGetDefaultAccount().GetAddress(), groupName, opt.Extra) return c.sendTxn(ctx, createGroupMsg, opt.TxOpts) } -// DeleteGroup send DeleteGroup txn to greenfield chain and return txn hash -func (c *client) DeleteGroup(ctx context.Context, groupName string, opt types.DeleteGroupOption) (string, error) { +// DeleteGroup - Delete a group on Greenfield blockchain. The sender MUST only be the group owner, group members or others would fail to send this transaction. +// +// Note: Deleting a group will result in granted permission revoked. Members within the group will no longer have access to resources (bucket, object) which granted permission on. +// +// - ctx: Context variables for the current API call. +// +// - groupName: The group name identifies the group. +// +// - opt: The options for customizing the transaction +// +// - ret1: Transaction hash return from blockchain. +// +// - ret3: Return error when the request failed, otherwise return nil. +func (c *Client) DeleteGroup(ctx context.Context, groupName string, opt types.DeleteGroupOption) (string, error) { deleteGroupMsg := storageTypes.NewMsgDeleteGroup(c.MustGetDefaultAccount().GetAddress(), groupName) return c.sendTxn(ctx, deleteGroupMsg, opt.TxOpts) } -// UpdateGroupMember support adding or removing members from the group and return the txn hash -func (c *client) UpdateGroupMember(ctx context.Context, groupName string, groupOwnerAddr string, +// UpdateGroupMember - Update a group by adding or removing members. The sender can be the group owner or any individual account(Principle) that +// has been granted permission by the group owner. +// +// Note: The group owner can only grant ACTION_UPDATE_GROUP_MEMBER permission to an individual account, there is no way to grant permission to a group to allow members +// within such group to manipulate another group or the group itself. +// +// - ctx: Context variables for the current API call. +// +// - groupName: The group name identifies the group. +// +// - groupOwnerAddr: The HEX-encoded string of the group owner address. +// +// - addAddresses: The HEX-encoded string list of the member addresses to be added. +// +// - removeAddresses: The HEX-encoded string list of the member addresses to be removed. +// +// - opt: The options for customizing the group members expiration time and transaction. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) UpdateGroupMember(ctx context.Context, groupName string, groupOwnerAddr string, addAddresses, removeAddresses []string, opts types.UpdateGroupMemberOption, ) (string, error) { groupOwner, err := sdk.AccAddressFromHexUnsafe(groupOwnerAddr) @@ -139,8 +161,20 @@ func (c *client) UpdateGroupMember(ctx context.Context, groupName string, groupO return c.sendTxn(ctx, updateGroupMsg, opts.TxOpts) } -// LeaveGroup make the member leave the specific group -func (c *client) LeaveGroup(ctx context.Context, groupName string, groupOwnerAddr string, opt types.LeaveGroupOption) (string, error) { +// LeaveGroup - Leave a group. A group member initially leaves a group. +// +// - ctx: Context variables for the current API call. +// +// - groupName: The group name identifies the group. +// +// - groupOwnerAddr: The HEX-encoded string of the group owner address. +// +// - opt: The options for customizing the transaction. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) LeaveGroup(ctx context.Context, groupName string, groupOwnerAddr string, opt types.LeaveGroupOption) (string, error) { groupOwner, err := sdk.AccAddressFromHexUnsafe(groupOwnerAddr) if err != nil { return "", err @@ -149,9 +183,18 @@ func (c *client) LeaveGroup(ctx context.Context, groupName string, groupOwnerAdd return c.sendTxn(ctx, leaveGroupMsg, opt.TxOpts) } -// HeadGroup query the groupInfo on chain, return the group info if exists -// return err info if group not exist -func (c *client) HeadGroup(ctx context.Context, groupName string, groupOwnerAddr string) (*storageTypes.GroupInfo, error) { +// HeadGroup - Query the groupInfo on chain, return the group info if exists otherwise error. +// +// - ctx: Context variables for the current API call. +// +// - groupName: The group name identifies the group. +// +// - groupOwnerAddr: The HEX-encoded string of the group owner address. +// +// - ret1: The group info details +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) HeadGroup(ctx context.Context, groupName string, groupOwnerAddr string) (*storageTypes.GroupInfo, error) { headGroupRequest := storageTypes.QueryHeadGroupRequest{ GroupOwner: groupOwnerAddr, GroupName: groupName, @@ -165,8 +208,18 @@ func (c *client) HeadGroup(ctx context.Context, groupName string, groupOwnerAddr return headGroupResponse.GroupInfo, nil } -// HeadGroupMember query the group member info on chain, return true if the member exists in group -func (c *client) HeadGroupMember(ctx context.Context, groupName string, groupOwnerAddr, headMemberAddr string) bool { +// HeadGroupMember - Query the group member info on chain. +// +// - ctx: Context variables for the current API call. +// +// - groupName: The group name identifies the group. +// +// - groupOwnerAddr: The HEX-encoded string of the group owner address. +// +// - eadMemberAddr: The HEX-encoded string of the group member address +// +// - ret: The boolean value indicates whether the group member exists +func (c *Client) HeadGroupMember(ctx context.Context, groupName string, groupOwnerAddr, headMemberAddr string) bool { headGroupRequest := storageTypes.QueryHeadGroupMemberRequest{ GroupName: groupName, GroupOwner: groupOwnerAddr, @@ -177,8 +230,22 @@ func (c *client) HeadGroupMember(ctx context.Context, groupName string, groupOwn return err == nil } -// PutGroupPolicy apply group policy to user specified by principalAddr, the sender need to be the owner of the group -func (c *client) PutGroupPolicy(ctx context.Context, groupName string, principalAddr string, +// PutGroupPolicy - Apply group policy to user specified by principalAddr, the sender needs to be the owner of the group. +// +// - ctx: Context variables for the current API call. +// +// - groupName: The group name identifies the group. +// +// - principalAddr: The HEX-encoded string of the principal address. +// +// - statements: Policies outline the specific details of permissions, including the Effect, ActionList, and Resources. +// +// - opt: The options for customizing the policy expiration time and transaction. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) PutGroupPolicy(ctx context.Context, groupName string, principalAddr string, statements []*permTypes.Statement, opt types.PutPolicyOption, ) (string, error) { sender := c.MustGetDefaultAccount().GetAddress() @@ -196,9 +263,18 @@ func (c *client) PutGroupPolicy(ctx context.Context, groupName string, principal return c.sendPutPolicyTxn(ctx, putPolicyMsg, opt.TxOpts) } -// GetBucketPolicyOfGroup get the bucket policy info of the group specified by group id -// it queries a bucket policy that grants permission to a group -func (c *client) GetBucketPolicyOfGroup(ctx context.Context, bucketName string, groupId uint64) (*permTypes.Policy, error) { +// GetBucketPolicyOfGroup - Get the bucket policy info of the group. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The bucket name identifies the bucket. +// +// - groupId: The group id identity the group. +// +// - ret1: The bucket policy. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetBucketPolicyOfGroup(ctx context.Context, bucketName string, groupId uint64) (*permTypes.Policy, error) { resource := gnfdTypes.NewBucketGRN(bucketName).String() queryPolicy := storageTypes.QueryPolicyForGroupRequest{ @@ -214,9 +290,20 @@ func (c *client) GetBucketPolicyOfGroup(ctx context.Context, bucketName string, return queryPolicyResp.Policy, nil } -// GetObjectPolicyOfGroup get the object policy info of the group specified by group id -// it queries an object policy that grants permission to a group -func (c *client) GetObjectPolicyOfGroup(ctx context.Context, bucketName, objectName string, groupId uint64) (*permTypes.Policy, error) { +// GetObjectPolicyOfGroup - Get the object policy info of the group. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The bucket name identifies the bucket. +// +// - objectName: The object name identifies the object. +// +// - groupId: The group id identity the group. +// +// - ret1: The object policy +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetObjectPolicyOfGroup(ctx context.Context, bucketName, objectName string, groupId uint64) (*permTypes.Policy, error) { resource := gnfdTypes.NewObjectGRN(bucketName, objectName) queryPolicy := storageTypes.QueryPolicyForGroupRequest{ Resource: resource.String(), @@ -231,8 +318,20 @@ func (c *client) GetObjectPolicyOfGroup(ctx context.Context, bucketName, objectN return queryPolicyResp.Policy, nil } -// DeleteGroupPolicy delete group policy of the principal, the sender need to be the owner of the group -func (c *client) DeleteGroupPolicy(ctx context.Context, groupName string, principalAddr string, opt types.DeletePolicyOption) (string, error) { +// DeleteGroupPolicy - Delete the group policy of the principal, the sender needs to be the owner of the group +// +// - ctx: Context variables for the current API call. +// +// - groupName: The group name identifies the group. +// +// - principalAddr: The HEX-encoded string of the principal address +// +// - opt: The options for customizing the transaction. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) DeleteGroupPolicy(ctx context.Context, groupName string, principalAddr string, opt types.DeletePolicyOption) (string, error) { sender := c.MustGetDefaultAccount().GetAddress() resource := gnfdTypes.NewGroupGRN(sender, groupName).String() @@ -246,8 +345,18 @@ func (c *client) DeleteGroupPolicy(ctx context.Context, groupName string, princi return c.sendDelPolicyTxn(ctx, sender, resource, principal, opt.TxOpts) } -// GetGroupPolicy get the group policy info of the user specified by principalAddr -func (c *client) GetGroupPolicy(ctx context.Context, groupName string, principalAddr string) (*permTypes.Policy, error) { +// GetGroupPolicy - Get the group policy info of the user. +// +// - ctx: Context variables for the current API call. +// +// - groupName: The group name identifies the group. +// +// - principalAddr: The HEX-encoded string of the principal address. +// +// - ret1: The group policy. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetGroupPolicy(ctx context.Context, groupName string, principalAddr string) (*permTypes.Policy, error) { _, err := sdk.AccAddressFromHexUnsafe(principalAddr) if err != nil { return nil, err @@ -268,8 +377,16 @@ func (c *client) GetGroupPolicy(ctx context.Context, groupName string, principal return queryPolicyResp.Policy, nil } -// ListGroup get the group list by name and prefix -func (c *client) ListGroup(ctx context.Context, name, prefix string, opts types.ListGroupsOptions) (types.ListGroupsResult, error) { +// ListGroup - Get the group list by name and prefix. It provides fuzzy searches by inputting a specific name and prefix. +// +// - prefix: The start of the search pattern. The system will only return groups that start with this prefix. +// +// - name: The ending of the search pattern. +// +// - ret1: The groups response. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) ListGroup(ctx context.Context, name, prefix string, opts types.ListGroupsOptions) (types.ListGroupsResult, error) { const ( MaximumGetGroupListLimit = 1000 MaximumGetGroupListOffset = 100000 @@ -354,7 +471,22 @@ func (c *client) ListGroup(ctx context.Context, name, prefix string, opts types. return listGroupsResult, nil } -func (c *client) RenewGroupMember(ctx context.Context, groupOwnerAddr, groupName string, +// RenewGroupMember - Renew a list group members and their expiration time. +// +// - ctx: Context variables for the current API call. +// +// - groupName: The group name identifies the group. +// +// - groupOwnerAddr: The HEX-encoded string of the group owner address. +// +// - memberAddresses: The HEX-encoded string list of the member addresses to be renewed. +// +// - opts: The options for customizing the transaction and each group member's expiration time. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) RenewGroupMember(ctx context.Context, groupOwnerAddr, groupName string, memberAddresses []string, opts types.RenewGroupMemberOption, ) (string, error) { groupOwner, err := sdk.AccAddressFromHexUnsafe(groupOwnerAddr) @@ -389,8 +521,14 @@ func (c *client) RenewGroupMember(ctx context.Context, groupOwnerAddr, groupName return c.sendTxn(ctx, msg, opts.TxOpts) } -// ListGroupMembers returns a list of members contained within the group specified by the group id, including those for which the user's expiration time has already elapsed -func (c *client) ListGroupMembers(ctx context.Context, groupID int64, opts types.GroupMembersPaginationOptions) (*types.GroupMembersResult, error) { +// ListGroupMembers - List members within a group, including those for which the user's expiration time has already elapsed. +// +// - groupId: The group id identifies a group. +// +// - ret1: Group members detail. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) ListGroupMembers(ctx context.Context, groupID int64, opts types.GroupMembersPaginationOptions) (*types.GroupMembersResult, error) { params := url.Values{} params.Set("group-members", "") params.Set("group-id", strconv.FormatInt(groupID, 10)) @@ -442,9 +580,16 @@ func (c *client) ListGroupMembers(ctx context.Context, groupID int64, opts types return groups, nil } -// ListGroupsByAccount returns a list of all groups that the user has joined, including those for which the user's expiration time has already elapsed -// By default, the user is the sender. Other users can be set using the option -func (c *client) ListGroupsByAccount(ctx context.Context, opts types.GroupsPaginationOptions) (*types.GroupsResult, error) { +// ListGroupsByAccount - List groups that a user has joined, including those which the user's expiration time has already elapsed +// +// - ctx: Context variables for the current API call. +// +// - opts: The query option, By default, the user is the sender. Other users can be set using the option +// +// - ret1: Groups details. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) ListGroupsByAccount(ctx context.Context, opts types.GroupsPaginationOptions) (*types.GroupsResult, error) { params := url.Values{} params.Set("user-groups", "") params.Set("start-after", opts.StartAfter) @@ -506,9 +651,16 @@ func (c *client) ListGroupsByAccount(ctx context.Context, opts types.GroupsPagin return groups, nil } -// ListGroupsByOwner returns a list of groups owned by the specified user, including those for which the user's expiration time has already elapsed -// By default, the user is the sender. Other users can be set using the option -func (c *client) ListGroupsByOwner(ctx context.Context, opts types.GroupsOwnerPaginationOptions) (*types.GroupsResult, error) { +// ListGroupsByOwner - List groups owned by the specified user, including those for which the user's expiration time has already elapsed +// +// - ctx: Context variables for the current API call. +// +// - opts: The query option, By default, the user is the sender. Other users can be set using the option +// +// - ret1: Groups details. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) ListGroupsByOwner(ctx context.Context, opts types.GroupsOwnerPaginationOptions) (*types.GroupsResult, error) { params := url.Values{} params.Set("owned-groups", "") params.Set("start-after", opts.StartAfter) @@ -608,7 +760,7 @@ func (m *gfSpListGroupsByGroupIDsResponse) UnmarshalXML(d *xml.Decoder, start xm // - ret1: The result of group info map by given group ids. // // - ret2: Return error when the request failed, otherwise return nil. -func (c *client) ListGroupsByGroupID(ctx context.Context, groupIDs []uint64, opts types.EndPointOptions) (types.ListGroupsByGroupIDResponse, error) { +func (c *Client) ListGroupsByGroupID(ctx context.Context, groupIDs []uint64, opts types.EndPointOptions) (types.ListGroupsByGroupIDResponse, error) { const MaximumListBucketsSize = 1000 if len(groupIDs) == 0 || len(groupIDs) > MaximumListBucketsSize { return types.ListGroupsByGroupIDResponse{}, nil diff --git a/client/api_object.go b/client/api_object.go index 5682504b..c8be5046 100644 --- a/client/api_object.go +++ b/client/api_object.go @@ -30,7 +30,9 @@ import ( "github.com/rs/zerolog/log" ) -type Object interface { +// IObjectClient interface defines functions related to object operations. +// The concept of "object" is the same as the concept of the object in AWS S3 storage. +type IObjectClient interface { GetCreateObjectApproval(ctx context.Context, createObjectMsg *storageTypes.MsgCreateObject) (*storageTypes.MsgCreateObject, error) CreateObject(ctx context.Context, bucketName, objectName string, reader io.Reader, opts types.CreateObjectOptions) (string, error) PutObject(ctx context.Context, bucketName, objectName string, objectSize int64, reader io.Reader, opts types.PutObjectOptions) error @@ -41,51 +43,26 @@ type Object interface { GetObject(ctx context.Context, bucketName, objectName string, opts types.GetObjectOptions) (io.ReadCloser, types.ObjectStat, error) FGetObject(ctx context.Context, bucketName, objectName, filePath string, opts types.GetObjectOptions) error FGetObjectResumable(ctx context.Context, bucketName, objectName, filePath string, opts types.GetObjectOptions) error - - // HeadObject query the objectInfo on chain to check th object id, return the object info if exists - // return err info if object not exist HeadObject(ctx context.Context, bucketName, objectName string) (*types.ObjectDetail, error) - // HeadObjectByID query the objectInfo on chain by object id, return the object info if exists - // return err info if object not exist HeadObjectByID(ctx context.Context, objID string) (*types.ObjectDetail, error) - // UpdateObjectVisibility update the visibility of the object UpdateObjectVisibility(ctx context.Context, bucketName, objectName string, visibility storageTypes.VisibilityType, opt types.UpdateObjectOption) (string, error) - // PutObjectPolicy apply object policy to the principal, return the txn hash - // The principal can be generated by NewPrincipalWithAccount or NewPrincipalWithGroupId PutObjectPolicy(ctx context.Context, bucketName, objectName string, principal types.Principal, statements []*permTypes.Statement, opt types.PutPolicyOption) (string, error) - // DeleteObjectPolicy delete the object policy of the principal, return the txn hash - // The principal can be generated by NewPrincipalWithAccount or NewPrincipalWithGroupId DeleteObjectPolicy(ctx context.Context, bucketName, objectName string, principal types.Principal, opt types.DeletePolicyOption) (string, error) - // GetObjectPolicy get the object policy info of the user specified by principalAddr. - // principalAddr indicates the HEX-encoded string of the principal address GetObjectPolicy(ctx context.Context, bucketName, objectName string, principalAddr string) (*permTypes.Policy, error) - // IsObjectPermissionAllowed check if the permission of the object is allowed to the user - // userAddr indicates the HEX-encoded string of the user address IsObjectPermissionAllowed(ctx context.Context, userAddr string, bucketName, objectName string, action permTypes.ActionType) (permTypes.Effect, error) ListObjects(ctx context.Context, bucketName string, opts types.ListObjectsOptions) (types.ListObjectsResult, error) - // ComputeHashRoots compute the integrity hash, content size and the redundancy type of the file - // If isSerial is true, compute the integrity hash using the serial way - // If isSerial is false or not provided, compute the integrity hash using the parallel way ComputeHashRoots(reader io.Reader, isSerial bool) ([][]byte, int64, storageTypes.RedundancyType, error) - - // CreateFolder creates an empty object used as folder. - // objectName must ending with a forward slash (/) character CreateFolder(ctx context.Context, bucketName, objectName string, opts types.CreateObjectOptions) (string, error) - // GetObjectUploadProgress return the status of the uploading object GetObjectUploadProgress(ctx context.Context, bucketName, objectName string) (string, error) - - // GetObjectResumableUploadOffset return the status of the uploading object GetObjectResumableUploadOffset(ctx context.Context, bucketName, objectName string) (uint64, error) - // ListObjectsByObjectID list objects by object ids ListObjectsByObjectID(ctx context.Context, objectIds []uint64, opts types.EndPointOptions) (types.ListObjectsByObjectIDResponse, error) - // ListObjectPolicies list object policies by object info and action type ListObjectPolicies(ctx context.Context, objectName, bucketName string, actionType uint32, opts types.ListObjectPoliciesOptions) (types.ListObjectPoliciesResponse, error) } // GetRedundancyParams query and return the data shards, parity shards and segment size of redundancy // configuration on chain -func (c *client) GetRedundancyParams() (uint32, uint32, uint64, error) { +func (c *Client) GetRedundancyParams() (uint32, uint32, uint64, error) { query := storageTypes.QueryParamsRequest{} queryResp, err := c.chainClient.StorageQueryClient.Params(context.Background(), &query) if err != nil { @@ -98,7 +75,7 @@ func (c *client) GetRedundancyParams() (uint32, uint32, uint64, error) { // GetParams query and return the data shards, parity shards and segment size of redundancy // configuration on chain -func (c *client) GetParams() (storageTypes.Params, error) { +func (c *Client) GetParams() (storageTypes.Params, error) { query := storageTypes.QueryParamsRequest{} queryResp, err := c.chainClient.StorageQueryClient.Params(context.Background(), &query) if err != nil { @@ -109,7 +86,7 @@ func (c *client) GetParams() (storageTypes.Params, error) { } // ComputeHashRoots return the integrity hash, content size and the redundancy type of the file -func (c *client) ComputeHashRoots(reader io.Reader, isSerial bool) ([][]byte, int64, storageTypes.RedundancyType, error) { +func (c *Client) ComputeHashRoots(reader io.Reader, isSerial bool) ([][]byte, int64, storageTypes.RedundancyType, error) { dataBlocks, parityBlocks, segSize, err := c.GetRedundancyParams() if reader == nil { return nil, 0, storageTypes.REDUNDANCY_EC_TYPE, errors.New("fail to compute hash, reader is nil") @@ -123,7 +100,7 @@ func (c *client) ComputeHashRoots(reader io.Reader, isSerial bool) ([][]byte, in // CreateObject get approval of creating object and send createObject txn to greenfield chain, // it returns the transaction hash value and error -func (c *client) CreateObject(ctx context.Context, bucketName, objectName string, +func (c *Client) CreateObject(ctx context.Context, bucketName, objectName string, reader io.Reader, opts types.CreateObjectOptions, ) (string, error) { if reader == nil { @@ -196,8 +173,20 @@ func (c *client) CreateObject(ctx context.Context, bucketName, objectName string return txnHash, nil } -// DeleteObject send DeleteBucket txn to greenfield chain and return txn hash -func (c *client) DeleteObject(ctx context.Context, bucketName, objectName string, opt types.DeleteObjectOption) (string, error) { +// DeleteObject - Send DeleteObject msg to greenfield chain and return txn hash. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The name of the bucket which contain the object. +// +// - objectName: The name of the object to be deleted. +// +// - opt: The Options for customizing the DeleteObject transaction. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error if delete bucket failed, otherwise return nil. +func (c *Client) DeleteObject(ctx context.Context, bucketName, objectName string, opt types.DeleteObjectOption) (string, error) { if err := s3util.CheckValidBucketName(bucketName); err != nil { return "", err } @@ -211,7 +200,7 @@ func (c *client) DeleteObject(ctx context.Context, bucketName, objectName string } // CancelCreateObject send CancelCreateObject txn to greenfield chain -func (c *client) CancelCreateObject(ctx context.Context, bucketName, objectName string, opt types.CancelCreateOption) (string, error) { +func (c *Client) CancelCreateObject(ctx context.Context, bucketName, objectName string, opt types.CancelCreateOption) (string, error) { if err := s3util.CheckValidBucketName(bucketName); err != nil { return "", err } @@ -226,7 +215,7 @@ func (c *client) CancelCreateObject(ctx context.Context, bucketName, objectName // PutObject supports the second stage of uploading the object to bucket. // txnHash should be the str which hex.encoding from txn hash bytes -func (c *client) PutObject(ctx context.Context, bucketName, objectName string, objectSize int64, +func (c *Client) PutObject(ctx context.Context, bucketName, objectName string, objectSize int64, reader io.Reader, opts types.PutObjectOptions, ) (err error) { if objectSize <= 0 { @@ -253,7 +242,7 @@ func (c *client) PutObject(ctx context.Context, bucketName, objectName string, o return c.putObjectResumable(ctx, bucketName, objectName, objectSize, reader, opts) } -func (c *client) putObject(ctx context.Context, bucketName, objectName string, objectSize int64, +func (c *Client) putObject(ctx context.Context, bucketName, objectName string, objectSize int64, reader io.Reader, opts types.PutObjectOptions, ) (err error) { if err := c.headSPObjectInfo(ctx, bucketName, objectName); err != nil { @@ -313,7 +302,7 @@ func DefaultUploadSegment(id int) error { return nil } -func (c *client) putObjectResumable(ctx context.Context, bucketName, objectName string, objectSize int64, +func (c *Client) putObjectResumable(ctx context.Context, bucketName, objectName string, objectSize int64, reader io.Reader, opts types.PutObjectOptions, ) (err error) { if err := c.headSPObjectInfo(ctx, bucketName, objectName); err != nil { @@ -440,7 +429,7 @@ func (c *client) putObjectResumable(ctx context.Context, bucketName, objectName return nil } -func (c *client) headSPObjectInfo(ctx context.Context, bucketName, objectName string) error { +func (c *Client) headSPObjectInfo(ctx context.Context, bucketName, objectName string) error { backoffDelay := types.HeadBackOffDelay for retry := 0; retry < types.MaxHeadTryTime; retry++ { _, err := c.getObjectStatusFromSP(ctx, bucketName, objectName) @@ -464,7 +453,7 @@ func (c *client) headSPObjectInfo(ctx context.Context, bucketName, objectName st } // FPutObject supports uploading object from local file -func (c *client) FPutObject(ctx context.Context, bucketName, objectName, filePath string, opts types.PutObjectOptions) (err error) { +func (c *Client) FPutObject(ctx context.Context, bucketName, objectName, filePath string, opts types.PutObjectOptions) (err error) { fReader, err := os.Open(filePath) // If any error fail quickly here. if err != nil { @@ -482,7 +471,7 @@ func (c *client) FPutObject(ctx context.Context, bucketName, objectName, filePat } // GetObject download s3 object payload and return the related object info -func (c *client) GetObject(ctx context.Context, bucketName, objectName string, +func (c *Client) GetObject(ctx context.Context, bucketName, objectName string, opts types.GetObjectOptions, ) (io.ReadCloser, types.ObjectStat, error) { if err := s3util.CheckValidBucketName(bucketName); err != nil { @@ -529,7 +518,7 @@ func (c *client) GetObject(ctx context.Context, bucketName, objectName string, } // FGetObject download s3 object payload adn write the object content into local file specified by filePath -func (c *client) FGetObject(ctx context.Context, bucketName, objectName, filePath string, opts types.GetObjectOptions) error { +func (c *Client) FGetObject(ctx context.Context, bucketName, objectName, filePath string, opts types.GetObjectOptions) error { // Verify if destination already exists. st, err := os.Stat(filePath) if err == nil { @@ -560,8 +549,8 @@ func (c *client) FGetObject(ctx context.Context, bucketName, objectName, filePat return nil } -// GetSegmentEnd calculates the end position -func GetSegmentEnd(begin int64, total int64, per int64) int64 { +// getSegmentEnd calculates the end position +func getSegmentEnd(begin int64, total int64, per int64) int64 { if begin+per > total { return total - 1 } @@ -569,7 +558,7 @@ func GetSegmentEnd(begin int64, total int64, per int64) int64 { } // FGetObjectResumable download s3 object payload with resumable download -func (c *client) FGetObjectResumable(ctx context.Context, bucketName, objectName, filePath string, opts types.GetObjectOptions) error { +func (c *Client) FGetObjectResumable(ctx context.Context, bucketName, objectName, filePath string, opts types.GetObjectOptions) error { // Get the object detailed meta for object whole size meta, err := c.HeadObject(ctx, bucketName, objectName) if err != nil { @@ -595,7 +584,7 @@ func (c *client) FGetObjectResumable(ctx context.Context, bucketName, objectName } maxSegmentSize = int64(params.GetMaxSegmentSize()) - // minPartSize: 16MB + // minPartSize: 32MB if opts.PartSize == 0 { partSize = types.MinPartSize } else { @@ -693,7 +682,7 @@ func (c *client) FGetObjectResumable(ctx context.Context, bucketName, objectName return err } - partEndOffset = GetSegmentEnd(partStartOffset, endOffset+1, partSize) + partEndOffset = getSegmentEnd(partStartOffset, endOffset+1, partSize) err = objectOption.SetRange(partStartOffset, partEndOffset) if err != nil { return err @@ -760,7 +749,7 @@ func getObjInfo(objectName string, h http.Header) (types.ObjectStat, error) { // HeadObject query the objectInfo on chain to check th object id, return the object info if exists // return err info if object not exist -func (c *client) HeadObject(ctx context.Context, bucketName, objectName string) (*types.ObjectDetail, error) { +func (c *Client) HeadObject(ctx context.Context, bucketName, objectName string) (*types.ObjectDetail, error) { queryHeadObjectRequest := storageTypes.QueryHeadObjectRequest{ BucketName: bucketName, ObjectName: objectName, @@ -778,7 +767,7 @@ func (c *client) HeadObject(ctx context.Context, bucketName, objectName string) // HeadObjectByID query the objectInfo on chain by object id, return the object info if exists // return err info if object not exist -func (c *client) HeadObjectByID(ctx context.Context, objID string) (*types.ObjectDetail, error) { +func (c *Client) HeadObjectByID(ctx context.Context, objID string) (*types.ObjectDetail, error) { headObjectRequest := storageTypes.QueryHeadObjectByIdRequest{ ObjectId: objID, } @@ -794,7 +783,7 @@ func (c *client) HeadObjectByID(ctx context.Context, objID string) (*types.Objec } // PutObjectPolicy apply object policy to the principal, return the txn hash -func (c *client) PutObjectPolicy(ctx context.Context, bucketName, objectName string, principalStr types.Principal, +func (c *Client) PutObjectPolicy(ctx context.Context, bucketName, objectName string, principalStr types.Principal, statements []*permTypes.Statement, opt types.PutPolicyOption, ) (string, error) { resource := gnfdTypes.NewObjectGRN(bucketName, objectName) @@ -811,7 +800,7 @@ func (c *client) PutObjectPolicy(ctx context.Context, bucketName, objectName str } // DeleteObjectPolicy delete the object policy of the principal -func (c *client) DeleteObjectPolicy(ctx context.Context, bucketName, objectName string, principalStr types.Principal, opt types.DeletePolicyOption) (string, error) { +func (c *Client) DeleteObjectPolicy(ctx context.Context, bucketName, objectName string, principalStr types.Principal, opt types.DeletePolicyOption) (string, error) { principal := &permTypes.Principal{} if err := principal.Unmarshal([]byte(principalStr)); err != nil { return "", err @@ -822,7 +811,7 @@ func (c *client) DeleteObjectPolicy(ctx context.Context, bucketName, objectName } // IsObjectPermissionAllowed check if the permission of the object is allowed to the user -func (c *client) IsObjectPermissionAllowed(ctx context.Context, userAddr string, +func (c *Client) IsObjectPermissionAllowed(ctx context.Context, userAddr string, bucketName, objectName string, action permTypes.ActionType, ) (permTypes.Effect, error) { _, err := sdk.AccAddressFromHexUnsafe(userAddr) @@ -845,7 +834,7 @@ func (c *client) IsObjectPermissionAllowed(ctx context.Context, userAddr string, } // GetObjectPolicy get the object policy info of the user specified by principalAddr -func (c *client) GetObjectPolicy(ctx context.Context, bucketName, objectName string, principalAddr string) (*permTypes.Policy, error) { +func (c *Client) GetObjectPolicy(ctx context.Context, bucketName, objectName string, principalAddr string) (*permTypes.Policy, error) { _, err := sdk.AccAddressFromHexUnsafe(principalAddr) if err != nil { return nil, err @@ -865,8 +854,18 @@ func (c *client) GetObjectPolicy(ctx context.Context, bucketName, objectName str return queryPolicyResp.Policy, nil } -// ListObjects return object list of the specific bucket -func (c *client) ListObjects(ctx context.Context, bucketName string, opts types.ListObjectsOptions) (types.ListObjectsResult, error) { +// ListObjects - Lists the object info of the bucket. If opts.ShowRemovedObject set to false, these objects will be skipped. +// +// - ctx: Context variables for the current API call. +// +// - bucketName: The bucket name identifies the bucket. +// +// - opts: The options to set the meta to list the objects +// +// - ret1: The result of list objects under specific bucket +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) ListObjects(ctx context.Context, bucketName string, opts types.ListObjectsOptions) (types.ListObjectsResult, error) { if err := s3util.CheckValidBucketName(bucketName); err != nil { return types.ListObjectsResult{}, err } @@ -970,7 +969,7 @@ func (c *client) ListObjects(ctx context.Context, bucketName string, opts types. } // GetCreateObjectApproval returns the signature info for the approval of preCreating resources -func (c *client) GetCreateObjectApproval(ctx context.Context, createObjectMsg *storageTypes.MsgCreateObject) (*storageTypes.MsgCreateObject, error) { +func (c *Client) GetCreateObjectApproval(ctx context.Context, createObjectMsg *storageTypes.MsgCreateObject) (*storageTypes.MsgCreateObject, error) { unsignedBytes := createObjectMsg.GetSignBytes() // set the action type @@ -1020,7 +1019,7 @@ func (c *client) GetCreateObjectApproval(ctx context.Context, createObjectMsg *s } // CreateFolder send create empty object txn to greenfield chain -func (c *client) CreateFolder(ctx context.Context, bucketName, objectName string, opts types.CreateObjectOptions) (string, error) { +func (c *Client) CreateFolder(ctx context.Context, bucketName, objectName string, opts types.CreateObjectOptions) (string, error) { if !strings.HasSuffix(objectName, "/") { return "", errors.New("failed to create folder. Folder names must end with a forward slash (/) character") } @@ -1031,7 +1030,7 @@ func (c *client) CreateFolder(ctx context.Context, bucketName, objectName string } // GetObjectUploadProgress return the status of object including the uploading progress -func (c *client) GetObjectUploadProgress(ctx context.Context, bucketName, objectName string) (string, error) { +func (c *Client) GetObjectUploadProgress(ctx context.Context, bucketName, objectName string) (string, error) { status, err := c.HeadObject(ctx, bucketName, objectName) if err != nil { return "", err @@ -1050,7 +1049,7 @@ func (c *client) GetObjectUploadProgress(ctx context.Context, bucketName, object } // GetObjectResumableUploadOffset return the status of object including the uploading progress -func (c *client) GetObjectResumableUploadOffset(ctx context.Context, bucketName, objectName string) (uint64, error) { +func (c *Client) GetObjectResumableUploadOffset(ctx context.Context, bucketName, objectName string) (uint64, error) { status, err := c.HeadObject(ctx, bucketName, objectName) if err != nil { return 0, err @@ -1070,7 +1069,7 @@ func (c *client) GetObjectResumableUploadOffset(ctx context.Context, bucketName, return 0, nil } -func (c *client) getObjectOffsetFromSP(ctx context.Context, bucketName, objectName string) (types.UploadOffset, error) { +func (c *Client) getObjectOffsetFromSP(ctx context.Context, bucketName, objectName string) (types.UploadOffset, error) { params := url.Values{} params.Set("upload-context", "") @@ -1112,7 +1111,7 @@ func (c *client) getObjectOffsetFromSP(ctx context.Context, bucketName, objectNa return objectOffset, nil } -func (c *client) getObjectStatusFromSP(ctx context.Context, bucketName, objectName string) (types.UploadProgress, error) { +func (c *Client) getObjectStatusFromSP(ctx context.Context, bucketName, objectName string) (types.UploadProgress, error) { params := url.Values{} params.Set("upload-progress", "") @@ -1150,7 +1149,7 @@ func (c *client) getObjectStatusFromSP(ctx context.Context, bucketName, objectNa return objectStatus, nil } -func (c *client) UpdateObjectVisibility(ctx context.Context, bucketName, objectName string, +func (c *Client) UpdateObjectVisibility(ctx context.Context, bucketName, objectName string, visibility storageTypes.VisibilityType, opt types.UpdateObjectOption, ) (string, error) { object, err := c.HeadObject(ctx, bucketName, objectName) @@ -1173,18 +1172,17 @@ func (c *client) UpdateObjectVisibility(ctx context.Context, bucketName, objectN return c.sendTxn(ctx, updateObjectMsg, opt.TxOpts) } -type GfSpListObjectsByIDsResponse map[uint64]*types.ObjectMeta +type listObjectsByIDsResponse map[uint64]*types.ObjectMeta -type ObjectEntry struct { +type objectEntry struct { Id uint64 Value *types.ObjectMeta } -func (m *GfSpListObjectsByIDsResponse) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { - *m = GfSpListObjectsByIDsResponse{} - //result := GfSpListObjectsByIDsResponse{} +func (m *listObjectsByIDsResponse) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *m = listObjectsByIDsResponse{} for { - var e ObjectEntry + var e objectEntry err := d.Decode(&e) if err == io.EOF { @@ -1198,10 +1196,20 @@ func (m *GfSpListObjectsByIDsResponse) UnmarshalXML(d *xml.Decoder, start xml.St return nil } -// ListObjectsByObjectID list objects by object ids -// By inputting a collection of object IDs, we can retrieve the corresponding object data. -// If the object is nonexistent or has been deleted, a null value will be returned -func (c *client) ListObjectsByObjectID(ctx context.Context, objectIds []uint64, opts types.EndPointOptions) (types.ListObjectsByObjectIDResponse, error) { +// ListObjectsByObjectID - List objects by object ids. If opts.ShowRemovedObject set to false, these objects will be skipped. +// +// By inputting a collection of object IDs, we can retrieve the corresponding object data. If the object is nonexistent or has been deleted, a null value will be returned +// +// - ctx: Context variables for the current API call. +// +// - objectIds: The list of object ids. +// +// - opts: The options to set the meta to list objects by object id. +// +// - ret1: The result of object info map by given object ids. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) ListObjectsByObjectID(ctx context.Context, objectIds []uint64, opts types.EndPointOptions) (types.ListObjectsByObjectIDResponse, error) { const MaximumListObjectsSize = 100 if len(objectIds) == 0 || len(objectIds) > MaximumListObjectsSize { return types.ListObjectsByObjectIDResponse{}, nil @@ -1258,7 +1266,7 @@ func (c *client) ListObjectsByObjectID(ctx context.Context, objectIds []uint64, objects := types.ListObjectsByObjectIDResponse{} bufStr := buf.String() - err = xml.Unmarshal([]byte(bufStr), (*GfSpListObjectsByIDsResponse)(&objects.Objects)) + err = xml.Unmarshal([]byte(bufStr), (*listObjectsByIDsResponse)(&objects.Objects)) if err != nil && objects.Objects == nil { log.Error().Msgf("the list of objects in object ids:%v failed: %s", objectIds, err.Error()) return types.ListObjectsByObjectIDResponse{}, err @@ -1267,8 +1275,24 @@ func (c *client) ListObjectsByObjectID(ctx context.Context, objectIds []uint64, return objects, nil } -// ListObjectPolicies list object policies by object info and action type -func (c *client) ListObjectPolicies(ctx context.Context, objectName, bucketName string, actionType uint32, opts types.ListObjectPoliciesOptions) (types.ListObjectPoliciesResponse, error) { +// ListObjectPolicies - List object policies by object info and action type. +// +// If the limit is set to 0, it will default to 50. If the limit exceeds 1000, only 1000 records will be returned. +// +// - ctx: Context variables for the current API call. +// +// - objectName: The object name identifies the object. +// +// - bucketName: The bucket name identifies the bucket. +// +// - actionType: The action type defines the requested action type of permission. +// +// - opts: The options to set the meta to list object policies +// +// - ret1: The result of object policy meta +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) ListObjectPolicies(ctx context.Context, objectName, bucketName string, actionType uint32, opts types.ListObjectPoliciesOptions) (types.ListObjectPoliciesResponse, error) { params := url.Values{} params.Set("object-policies", "") // StartAfter is used to input the policy id for pagination purposes diff --git a/client/api_off_chain_auth.go b/client/api_off_chain_auth.go index cb3f40b1..f1d3a276 100644 --- a/client/api_off_chain_auth.go +++ b/client/api_off_chain_auth.go @@ -24,38 +24,51 @@ import ( "golang.org/x/crypto/blake2b" ) -type OffChainAuth interface { +// IAuthClient - Client APIs for register Greenfield off chain auth keys and make signatures. +type IAuthClient interface { RegisterEDDSAPublicKey(spAddress string, spEndpoint string) (string, error) - OffChainAuthSign(unsignBytes []byte) string + GetNextNonce(spEndpoint string) (string, error) + OffChainAuthSign(unsignedBytes []byte) string } -func (c *client) OffChainAuthSign(unsignBytes []byte) string { - sk, _ := GenerateEddsaPrivateKey(c.offChainAuthOption.Seed) +// OffChainAuthSign - Generate EdDSA private key according to a preconfigured seed and then make the signature for given input. +// +// - unsignedBytes: The content which needs to be signed by client's EdDSA private key +// +// - ret1: The signature made by EdDSA private key of the Client. +func (c *Client) OffChainAuthSign(unsignedBytes []byte) string { + sk, _ := generateEddsaPrivateKey(c.offChainAuthOption.Seed) hFunc := mimc.NewMiMC() - sig, _ := sk.Sign(unsignBytes, hFunc) + sig, _ := sk.Sign(unsignedBytes, hFunc) authString := fmt.Sprintf("%s,Signature=%v", httplib.Gnfd1Eddsa, hex.EncodeToString(sig)) return authString } -// RequestNonceResp is the structure for off chain auth nonce response -type RequestNonceResp struct { +// requestNonceResp is the structure for off chain auth nonce response. +type requestNonceResp struct { CurrentNonce int32 `xml:"CurrentNonce"` NextNonce int32 `xml:"NextNonce"` CurrentPublicKey string `xml:"CurrentPublicKey"` ExpiryDate int64 `xml:"ExpiryDate"` } -// GetNextNonce get the nonce value by giving user account and domain -func (c *client) GetNextNonce(spEndpoint string) (string, error) { +// GetNextNonce - Get the nonce value by giving user account and domain. +// +// - spEndpoint: The sp endpoint where the client means to get the next nonce +// +// - ret1: The next nonce value for the Client if it needs to register a new EdDSA public key +// +// - ret2: Return error when getting next nonce failed, otherwise return nil. +func (c *Client) GetNextNonce(spEndpoint string) (string, error) { header := make(map[string]string) header["X-Gnfd-User-Address"] = c.defaultAccount.GetAddress().String() header["X-Gnfd-App-Domain"] = c.offChainAuthOption.Domain - response, err := HttpGetWithHeader(spEndpoint+"/auth/request_nonce", header) + response, err := httpGetWithHeader(spEndpoint+"/auth/request_nonce", header) if err != nil { return "0", err } - authNonce := RequestNonceResp{} + authNonce := requestNonceResp{} // decode the xml content from response body err = xml.NewDecoder(bytes.NewBufferString(response)).Decode(&authNonce) if err != nil { @@ -65,7 +78,7 @@ func (c *client) GetNextNonce(spEndpoint string) (string, error) { } const ( - UnsignedContentTemplate string = `%s wants you to sign in with your BNB Greenfield account: + unsignedContentTemplate string = `%s wants you to sign in with your BNB Greenfield account: %s Register your identity public key %s @@ -79,7 +92,25 @@ Resources: - SP %s (name: SP_001) with nonce: %s` ) -func (c *client) RegisterEDDSAPublicKey(spAddress string, spEndpoint string) (string, error) { +// RegisterEDDSAPublicKey - Register EdDSA public key of this client for the given sp address and spEndpoint. +// +// To enable EdDSA authentication, you need to config OffChainAuthOption for the client. +// The overall register process could be referred to https://docs.bnbchain.org/greenfield-docs/docs/guide/storage-provider/modules/authenticator#workflow. +// +// The EdDSA registering process is typically used in a website, e.g. https://dcellar.io, +// which obtains a user's signature via a wallet and then posts the user's EdDSA public key to a sp. +// +// Here we also provide an SDK method to implement this process, because sometimes you might want to test if a given SP provides correct EdDSA authentication or not. +// It also helps if you want implement it on a non-browser environment. +// +// - spAddress: The sp operator address, to which this API will register client's EdDSA public key. It can be found via https://docs.bnbchain.org/greenfield-docs/docs/greenfield-api/storage-providers . +// +// - spEndpoint: The sp endpoint, to which this API will register client's EdDSA public key. It can be found via https://docs.bnbchain.org/greenfield-docs/docs/greenfield-api/storage-providers . +// +// - ret1: The register result when invoking SP UpdateUserPublicKey API. +// +// - ret2: Return error when registering failed, otherwise return nil. +func (c *Client) RegisterEDDSAPublicKey(spAddress string, spEndpoint string) (string, error) { appDomain := c.offChainAuthOption.Domain eddsaSeed := c.offChainAuthOption.Seed nextNonce, err := c.GetNextNonce(spEndpoint) @@ -87,14 +118,14 @@ func (c *client) RegisterEDDSAPublicKey(spAddress string, spEndpoint string) (st return "", err } // get the EDDSA private and public key - userEddsaPublicKeyStr := GetEddsaCompressedPublicKey(eddsaSeed) + userEddsaPublicKeyStr := getEddsaCompressedPublicKey(eddsaSeed) log.Info().Msg("userEddsaPublicKeyStr is " + userEddsaPublicKeyStr) IssueDate := time.Now().Format(time.RFC3339) - // ExpiryDate formate := "2023-06-27T06:35:24Z" + // ExpiryDate format := "2023-06-27T06:35:24Z" ExpiryDate := time.Now().Add(time.Hour * 24).Format(time.RFC3339) - unSignedContent := fmt.Sprintf(UnsignedContentTemplate, appDomain, c.defaultAccount.GetAddress().String(), userEddsaPublicKeyStr, appDomain, IssueDate, ExpiryDate, spAddress, nextNonce) + unSignedContent := fmt.Sprintf(unsignedContentTemplate, appDomain, c.defaultAccount.GetAddress().String(), userEddsaPublicKeyStr, appDomain, IssueDate, ExpiryDate, spAddress, nextNonce) unSignedContentHash := accounts.TextHash([]byte(unSignedContent)) sig, _ := c.defaultAccount.GetKeyManager().Sign(unSignedContentHash) @@ -108,12 +139,12 @@ func (c *client) RegisterEDDSAPublicKey(spAddress string, spEndpoint string) (st headers["authorization"] = authString headers["origin"] = appDomain headers["x-gnfd-user-address"] = c.defaultAccount.GetAddress().String() - jsonResult, error1 := HttpPostWithHeader(spEndpoint+"/auth/update_key", "{}", headers) + jsonResult, error1 := httpPostWithHeader(spEndpoint+"/auth/update_key", "{}", headers) return jsonResult, error1 } -func HttpGetWithHeader(url string, header map[string]string) (string, error) { +func httpGetWithHeader(url string, header map[string]string) (string, error) { req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { return "", err @@ -136,7 +167,7 @@ func HttpGetWithHeader(url string, header map[string]string) (string, error) { return string(body), err } -func HttpPostWithHeader(url string, jsonStr string, header map[string]string) (string, error) { +func httpPostWithHeader(url string, jsonStr string, header map[string]string) (string, error) { json := []byte(jsonStr) req, err := http.NewRequest("POST", url, bytes.NewBuffer(json)) if err != nil { @@ -161,8 +192,8 @@ func HttpPostWithHeader(url string, jsonStr string, header map[string]string) (s return string(body), err } -func GetEddsaCompressedPublicKey(seed string) string { - sk, err := GenerateEddsaPrivateKey(seed) +func getEddsaCompressedPublicKey(seed string) string { + sk, err := generateEddsaPrivateKey(seed) if err != nil { return err.Error() } @@ -171,16 +202,12 @@ func GetEddsaCompressedPublicKey(seed string) string { return hex.EncodeToString(buf.Bytes()) } -type ( - PrivateKey = eddsa.PrivateKey -) - -// GenerateEddsaPrivateKey: generate eddsa private key -func GenerateEddsaPrivateKey(seed string) (sk *PrivateKey, err error) { +// generateEddsaPrivateKey: generate eddsa private key +func generateEddsaPrivateKey(seed string) (sk *eddsa.PrivateKey, err error) { buf := make([]byte, 32) copy(buf, seed) reader := bytes.NewReader(buf) - sk, err = GenerateKey(reader) + sk, err = generateKey(reader) return sk, err } @@ -188,15 +215,13 @@ const ( sizeFr = fr.Bytes ) -type PublicKey = eddsa.PublicKey - -func GenerateKey(r io.Reader) (*PrivateKey, error) { +func generateKey(r io.Reader) (*eddsa.PrivateKey, error) { c := twistededwards.GetEdwardsCurve() var ( randSrc = make([]byte, 32) scalar = make([]byte, 32) - pub PublicKey + pub eddsa.PublicKey ) // hash(h) = private_key || random_source, on 32 bytes each @@ -245,7 +270,7 @@ func GenerateKey(r io.Reader) (*PrivateKey, error) { subtle.ConstantTimeCopy(1, res[sizeFr:2*sizeFr], scalar[:]) subtle.ConstantTimeCopy(1, res[2*sizeFr:], randSrc[:]) - sk := &PrivateKey{} + sk := &eddsa.PrivateKey{} // make sure sk is not nil _, err = sk.SetBytes(res[:]) diff --git a/client/api_payment.go b/client/api_payment.go index 4d43fec1..410fafc9 100644 --- a/client/api_payment.go +++ b/client/api_payment.go @@ -20,17 +20,25 @@ import ( "github.com/bnb-chain/greenfield-go-sdk/types" ) -type Payment interface { +// IPaymentClient - Client APIs for operating and querying Greenfield payment accounts and stream records. +type IPaymentClient interface { GetStreamRecord(ctx context.Context, streamAddress string) (*paymentTypes.StreamRecord, error) - Deposit(ctx context.Context, toAddress string, amount math.Int, txOption gnfdSdkTypes.TxOption) (string, error) Withdraw(ctx context.Context, fromAddress string, amount math.Int, txOption gnfdSdkTypes.TxOption) (string, error) DisableRefund(ctx context.Context, paymentAddress string, txOption gnfdSdkTypes.TxOption) (string, error) ListUserPaymentAccounts(ctx context.Context, opts types.ListUserPaymentAccountsOptions) (types.ListUserPaymentAccountsResult, error) } -// GetStreamRecord retrieves stream record information for a given stream address. -func (c *client) GetStreamRecord(ctx context.Context, streamAddress string) (*paymentTypes.StreamRecord, error) { +// GetStreamRecord - Retrieve stream record information for a given stream address. +// +// - ctx: Context variables for the current API call. +// +// - streamAddress: The address of the stream record to be queried. +// +// - ret1: The stream record information, including balances and net flow rate. +// +// - ret2: Return error when getting challenge info failed, otherwise return nil. +func (c *Client) GetStreamRecord(ctx context.Context, streamAddress string) (*paymentTypes.StreamRecord, error) { accAddress, err := sdk.AccAddressFromHexUnsafe(streamAddress) if err != nil { return nil, err @@ -42,8 +50,20 @@ func (c *client) GetStreamRecord(ctx context.Context, streamAddress string) (*pa return &pa.StreamRecord, nil } -// Deposit deposits BNB to a stream account. -func (c *client) Deposit(ctx context.Context, toAddress string, amount math.Int, txOption gnfdSdkTypes.TxOption) (string, error) { +// Deposit - Deposit BNB to a payment account. +// +// - ctx: Context variables for the current API call. +// +// - toAddress: The address of the stream record to receive the deposit. +// +// - amount: The amount to deposit. +// +// - txOption: The options for sending the tx. +// +// - ret1: The response of Greenfield transaction. +// +// - ret2: Return error when deposit tx failed, otherwise return nil. +func (c *Client) Deposit(ctx context.Context, toAddress string, amount math.Int, txOption gnfdSdkTypes.TxOption) (string, error) { accAddress, err := sdk.AccAddressFromHexUnsafe(toAddress) if err != nil { return "", err @@ -60,8 +80,25 @@ func (c *client) Deposit(ctx context.Context, toAddress string, amount math.Int, return tx.TxResponse.TxHash, nil } -// Withdraw withdraws BNB from a stream account. -func (c *client) Withdraw(ctx context.Context, fromAddress string, amount math.Int, txOption gnfdSdkTypes.TxOption) (string, error) { +// Withdraw - Withdraws BNB from a payment account. +// +// Withdrawal will trigger settlement, i.e., updating static balance and buffer balance. +// If the withdrawal amount is greater than the static balance after settlement it will fail. +// If the withdrawal amount is equal to or greater than 100BNB, it will be timelock-ed for 1 day duration. +// And after the duration, a message without `from` field should be sent to get the funds. +// +// - ctx: Context variables for the current API call. +// +// - fromAddress: The address of the stream record to withdraw from. +// +// - amount: The amount to withdraw. +// +// - txOption: The options for sending the tx. +// +// - ret1: The response of Greenfield transaction. +// +// - ret2: Return error when withdrawal tx failed, otherwise return nil. +func (c *Client) Withdraw(ctx context.Context, fromAddress string, amount math.Int, txOption gnfdSdkTypes.TxOption) (string, error) { accAddress, err := sdk.AccAddressFromHexUnsafe(fromAddress) if err != nil { return "", err @@ -78,8 +115,20 @@ func (c *client) Withdraw(ctx context.Context, fromAddress string, amount math.I return tx.TxResponse.TxHash, nil } -// DisableRefund disables refund for a stream account. -func (c *client) DisableRefund(ctx context.Context, paymentAddress string, txOption gnfdSdkTypes.TxOption) (string, error) { +// DisableRefund - Disable refund/withdrawal for a payment account. +// +// After disabling withdrawal of a payment account, no more withdrawal can be executed. The action cannot be reverted. +// +// - ctx: Context variables for the current API call. +// +// - paymentAddress: The address of the payment account to disable refund/withdrawal. +// +// - txOption: The options for sending the tx. +// +// - ret1: The response of Greenfield transaction. +// +// - ret2: Return error when disable refund tx failed, otherwise return nil. +func (c *Client) DisableRefund(ctx context.Context, paymentAddress string, txOption gnfdSdkTypes.TxOption) (string, error) { accAddress, err := sdk.AccAddressFromHexUnsafe(paymentAddress) if err != nil { return "", err @@ -95,8 +144,16 @@ func (c *client) DisableRefund(ctx context.Context, paymentAddress string, txOpt return tx.TxResponse.TxHash, nil } -// ListUserPaymentAccounts list payment info by user address -func (c *client) ListUserPaymentAccounts(ctx context.Context, opts types.ListUserPaymentAccountsOptions) (types.ListUserPaymentAccountsResult, error) { +// ListUserPaymentAccounts - List payment info by a user address. +// +// - ctx: Context variables for the current API call. +// +// - opts: The options to define the user address for querying. +// +// - ret1: The response of streams records for the user address. +// +// - ret2: Return error when querying payment accounts failed, otherwise return nil. +func (c *Client) ListUserPaymentAccounts(ctx context.Context, opts types.ListUserPaymentAccountsOptions) (types.ListUserPaymentAccountsResult, error) { params := url.Values{} params.Set("user-payments", "") diff --git a/client/api_proposal.go b/client/api_proposal.go index 87204d88..449e5d33 100644 --- a/client/api_proposal.go +++ b/client/api_proposal.go @@ -13,13 +13,32 @@ import ( govTypesV1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" ) -type Proposal interface { +type IProposalClient interface { SubmitProposal(ctx context.Context, msgs []sdk.Msg, depositAmount math.Int, title, summary string, opts types.SubmitProposalOptions) (uint64, string, error) VoteProposal(ctx context.Context, proposalID uint64, voteOption govTypesV1.VoteOption, opts types.VoteProposalOptions) (string, error) GetProposal(ctx context.Context, proposalID uint64) (*govTypesV1.Proposal, error) } -func (c *client) SubmitProposal(ctx context.Context, msgs []sdk.Msg, depositAmount math.Int, title, summary string, opts types.SubmitProposalOptions) (uint64, string, error) { +// SubmitProposal - Submit a proposal to Greenfield. +// +// - ctx: Context variables for the current API call. +// +// - msgs: The messages to be executed when the proposal is passed. +// +// - depositAmount: The amount of BNB to deposit to the proposal. +// +// - title: The title of the proposal. +// +// - summary: The summary of the proposal. +// +// - opts: The options of the proposal. +// +// - ret1: Proposal id of the submitted proposal. +// +// - ret2: Transaction hash of the transaction. +// +// - ret3: Return error if the transaction failed, otherwise return nil. +func (c *Client) SubmitProposal(ctx context.Context, msgs []sdk.Msg, depositAmount math.Int, title, summary string, opts types.SubmitProposalOptions) (uint64, string, error) { msgSubmitProposal, err := govTypesV1.NewMsgSubmitProposal(msgs, sdk.NewCoins(sdk.NewCoin(gnfdSdkTypes.Denom, depositAmount)), c.defaultAccount.GetAddress().String(), opts.Metadata, title, summary) if err != nil { return 0, "", err @@ -28,7 +47,7 @@ func (c *client) SubmitProposal(ctx context.Context, msgs []sdk.Msg, depositAmou if err != nil { return 0, "", err } - txResp, err := c.BroadcastTx(ctx, []sdk.Msg{msgSubmitProposal}, &opts.TxOption) + txResp, err := c.BroadcastTx(ctx, []sdk.Msg{msgSubmitProposal}, &opts.TxOpts) if err != nil { return 0, "", err } @@ -53,16 +72,38 @@ func (c *client) SubmitProposal(ctx context.Context, msgs []sdk.Msg, depositAmou return 0, txResp.TxResponse.TxHash, types.ErrorProposalIDNotFound } -func (c *client) VoteProposal(ctx context.Context, proposalID uint64, voteOption govTypesV1.VoteOption, opts types.VoteProposalOptions) (string, error) { +// VoteProposal - Vote for the proposal. +// +// - ctx: Context variables for the current API call. +// +// - proposalID: The proposal id to vote for. +// +// - voteOption: The vote option for the vote. +// +// - opts: The options of the transaction. +// +// - ret1: Transaction hash of the transaction. +// +// - ret2: Return error if the transaction failed, otherwise return nil. +func (c *Client) VoteProposal(ctx context.Context, proposalID uint64, voteOption govTypesV1.VoteOption, opts types.VoteProposalOptions) (string, error) { msgVote := govTypesV1.NewMsgVote(c.MustGetDefaultAccount().GetAddress(), proposalID, voteOption, opts.Metadata) - resp, err := c.BroadcastTx(ctx, []sdk.Msg{msgVote}, &opts.TxOption) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{msgVote}, &opts.TxOpts) if err != nil { return "", err } return resp.TxResponse.TxHash, nil } -func (c *client) GetProposal(ctx context.Context, proposalID uint64) (*govTypesV1.Proposal, error) { +// GetProposal - Get the proposal by proposal id. +// +// - ctx: Context variables for the current API call. +// +// - proposalID: The proposal id to vote for. +// +// - ret1: Proposal by the queried proposal id. +// +// - ret2: Return error if the query failed, otherwise return nil. +func (c *Client) GetProposal(ctx context.Context, proposalID uint64) (*govTypesV1.Proposal, error) { resp, err := c.chainClient.GovQueryClientV1.Proposal(ctx, &govTypesV1.QueryProposalRequest{ProposalId: proposalID}) if err != nil { return nil, nil diff --git a/client/api_sp.go b/client/api_sp.go index 144590ab..91cf0cb9 100644 --- a/client/api_sp.go +++ b/client/api_sp.go @@ -20,28 +20,28 @@ import ( govTypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) -type SP interface { - // ListStorageProviders return the storage provider info on chain - // isInService indicates if only display the sp with STATUS_IN_SERVICE status +// ISPClient interface defines basic functions related to Storage Provider. +type ISPClient interface { ListStorageProviders(ctx context.Context, isInService bool) ([]spTypes.StorageProvider, error) - // GetStorageProviderInfo return the sp info with the sp chain address GetStorageProviderInfo(ctx context.Context, SPAddr sdk.AccAddress) (*spTypes.StorageProvider, error) - // GetStoragePrice returns the storage price for a particular storage provider, including update time, read price, store price and .etc. GetStoragePrice(ctx context.Context, SPAddr string) (*spTypes.SpStoragePrice, error) - // GetGlobalSpStorePrice returns the global storage price, including update time and store price GetGlobalSpStorePrice(ctx context.Context) (*spTypes.GlobalSpStorePrice, error) - // GrantDepositForStorageProvider submit a grant transaction to allow gov module account to deduct the specified number of tokens GrantDepositForStorageProvider(ctx context.Context, spAddr string, depositAmount math.Int, opts types.GrantDepositForStorageProviderOptions) (string, error) - // CreateStorageProvider submits a proposal to create a storage provider to the greenfield blockchain, and it returns a proposal ID CreateStorageProvider(ctx context.Context, fundingAddr, sealAddr, approvalAddr, gcAddr, maintenanceAddr, blsPubKey, blsProof, endpoint string, depositAmount math.Int, description spTypes.Description, opts types.CreateStorageProviderOptions) (uint64, string, error) - // UpdateSpStoragePrice updates the read price, storage price and free read quota for a particular storage provider - UpdateSpStoragePrice(ctx context.Context, spAddr string, readPrice, storePrice sdk.Dec, freeReadQuota uint64, TxOption gnfdSdkTypes.TxOption) (string, error) - // UpdateSpStatus set an SP status between STATUS_IN_SERVICE and STATUS_IN_MAINTENANCE, duration is requested time an SP wish to stay in maintenance mode - // for setting to STATUS_IN_SERVICE, duration is set to 0 - UpdateSpStatus(ctx context.Context, spAddr string, status spTypes.Status, duration int64, TxOption gnfdSdkTypes.TxOption) (string, error) + UpdateSpStoragePrice(ctx context.Context, spAddr string, readPrice, storePrice sdk.Dec, freeReadQuota uint64, txOption gnfdSdkTypes.TxOption) (string, error) + UpdateSpStatus(ctx context.Context, spAddr string, status spTypes.Status, duration int64, txOption gnfdSdkTypes.TxOption) (string, error) } -func (c *client) GetStoragePrice(ctx context.Context, spAddr string) (*spTypes.SpStoragePrice, error) { +// GetStoragePrice - Get the storage price details for a particular storage provider, including update time, read price, store price and .etc. +// +// - ctx: Context variables for the current API call. +// +// - spAddr: The HEX-encoded string of the storage provider address. +// +// - ret1: The specified storage provider price detail. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetStoragePrice(ctx context.Context, spAddr string) (*spTypes.SpStoragePrice, error) { spAcc, err := sdk.AccAddressFromHexUnsafe(spAddr) if err != nil { return nil, err @@ -55,7 +55,14 @@ func (c *client) GetStoragePrice(ctx context.Context, spAddr string) (*spTypes.S return &resp.SpStoragePrice, nil } -func (c *client) GetGlobalSpStorePrice(ctx context.Context) (*spTypes.GlobalSpStorePrice, error) { +// GetGlobalSpStorePrice - Get the global storage price details, including update time and store price. +// +// - ctx: Context variables for the current API call. +// +// - ret1: The global storage provider price detail. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetGlobalSpStorePrice(ctx context.Context) (*spTypes.GlobalSpStorePrice, error) { resp, err := c.chainClient.QueryGlobalSpStorePriceByTime(ctx, &spTypes.QueryGlobalSpStorePriceByTimeRequest{ Timestamp: 0, }) @@ -65,9 +72,16 @@ func (c *client) GetGlobalSpStorePrice(ctx context.Context) (*spTypes.GlobalSpSt return &resp.GlobalSpStorePrice, nil } -// ListStorageProviders return the storage provider info on chain -// isInService indicates if only display the sp with STATUS_IN_SERVICE status -func (c *client) ListStorageProviders(ctx context.Context, isInService bool) ([]spTypes.StorageProvider, error) { +// ListStorageProviders - List the storage providers info on chain. +// +// - ctx: Context variables for the current API call. +// +// - isInService: The boolean value indicates if only display the sp with STATUS_IN_SERVICE status. +// +// - ret1: The global storage provider price detail. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) ListStorageProviders(ctx context.Context, isInService bool) ([]spTypes.StorageProvider, error) { request := &spTypes.QueryStorageProvidersRequest{} gnfdRep, err := c.chainClient.StorageProviders(ctx, request) if err != nil { @@ -86,10 +100,18 @@ func (c *client) ListStorageProviders(ctx context.Context, isInService bool) ([] return spInfoList, nil } -// GetStorageProviderInfo return the sp info with the sp chain address -func (c *client) GetStorageProviderInfo(ctx context.Context, SPAddr sdk.AccAddress) (*spTypes.StorageProvider, error) { +// GetStorageProviderInfo - Get the specified storage providers info on chain. +// +// - ctx: Context variables for the current API call. +// +// - spAddr: The HEX-encoded string of the storage provider address. +// +// - ret1: The Storage provider detail. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GetStorageProviderInfo(ctx context.Context, spAddr sdk.AccAddress) (*spTypes.StorageProvider, error) { request := &spTypes.QueryStorageProviderByOperatorAddressRequest{ - OperatorAddress: SPAddr.String(), + OperatorAddress: spAddr.String(), } gnfdRep, err := c.chainClient.StorageProviderByOperatorAddress(ctx, request) @@ -100,7 +122,7 @@ func (c *client) GetStorageProviderInfo(ctx context.Context, SPAddr sdk.AccAddre return gnfdRep.StorageProvider, nil } -func (c *client) refreshStorageProviders(ctx context.Context) error { +func (c *Client) refreshStorageProviders(ctx context.Context) error { gnfdRep, err := c.chainClient.StorageProviders(ctx, &spTypes.QueryStorageProvidersRequest{Pagination: &query.PageRequest{Limit: math2.MaxUint64}}) if err != nil { return err @@ -132,8 +154,38 @@ func (c *client) refreshStorageProviders(ctx context.Context) error { return nil } -// CreateStorageProvider will submit a CreateStorageProvider proposal and return proposalID, TxHash and err if it has. -func (c *client) CreateStorageProvider(ctx context.Context, fundingAddr, sealAddr, approvalAddr, gcAddr, maintenanceAddr, blsPubKey, blsProof, endpoint string, depositAmount math.Int, description spTypes.Description, opts types.CreateStorageProviderOptions) (uint64, string, error) { +// CreateStorageProvider - Submit a CreateStorageProvider proposal and return proposalID, TxHash and err if it has. +// +// - ctx: Context variables for the current API call. +// +// - fundingAddr: The HEX-encoded string of the storage provider funding address, Used to deposit staking tokens and receive earnings. +// +// - sealAddr: The HEX-encoded string of the storage provider seal address, Used to seal the user's object. +// +// - approvalAddr: The HEX-encoded string of the storage provider approval address, Used to approve user's requests. +// +// - gcAddr: The HEX-encoded string of the storage provider gc address, it is a special address for sp and is used by sp to clean up local expired or unwanted storage. +// +// - maintenanceAddr: The HEX-encoded string of the storage provider maintenance address, it is used for SP self-testing while in maintenance mode. +// +// - blsPubKey: The HEX-encoded string of the storage provider bls public key. +// +// - blsProof: The HEX-encoded string of the storage provider bls signature. +// +// - endpoint: Storage Provider endpoint. +// +// - depositAmount: The requested amount for a proposal. +// +// - description: Description for the SP. +// +// - opts: options to specify the SP prices, and proposal details. +// +// - ret1: Proposal ID. +// +// - ret2: Transaction hash return from blockchain. +// +// - ret3: Return error when the request failed, otherwise return nil. +func (c *Client) CreateStorageProvider(ctx context.Context, fundingAddr, sealAddr, approvalAddr, gcAddr, maintenanceAddr, blsPubKey, blsProof, endpoint string, depositAmount math.Int, description spTypes.Description, opts types.CreateStorageProviderOptions) (uint64, string, error) { defaultAccount := c.MustGetDefaultAccount() govModuleAddress, err := c.GetModuleAccountByName(ctx, govTypes.ModuleName) if err != nil { @@ -198,10 +250,23 @@ func (c *client) CreateStorageProvider(ctx context.Context, fundingAddr, sealAdd return 0, "", err } - return c.SubmitProposal(ctx, []sdk.Msg{msgCreateStorageProvider}, opts.ProposalDepositAmount, opts.ProposalTitle, opts.ProposalSummary, types.SubmitProposalOptions{Metadata: opts.ProposalMetaData, TxOption: opts.TxOption}) + return c.SubmitProposal(ctx, []sdk.Msg{msgCreateStorageProvider}, opts.ProposalDepositAmount, opts.ProposalTitle, opts.ProposalSummary, types.SubmitProposalOptions{Metadata: opts.ProposalMetaData, TxOpts: opts.TxOpts}) } -func (c *client) GrantDepositForStorageProvider(ctx context.Context, spAddr string, depositAmount math.Int, opts types.GrantDepositForStorageProviderOptions) (string, error) { +// GrantDepositForStorageProvider - Grant transaction to allow Gov module account to deduct the specified number of tokens. +// +// - ctx: Context variables for the current API call. +// +// - spAddr: The HEX-encoded string of the storage provider address. +// +// - depositAmount: The allowance of fee that allows grantee to spend up from the account of Granter. +// +// - opts: The options for customizing the transaction. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) GrantDepositForStorageProvider(ctx context.Context, spAddr string, depositAmount math.Int, opts types.GrantDepositForStorageProviderOptions) (string, error) { granter := c.MustGetDefaultAccount() govModuleAddress, err := c.GetModuleAccountByName(ctx, govTypes.ModuleName) if err != nil { @@ -222,14 +287,31 @@ func (c *client) GrantDepositForStorageProvider(ctx context.Context, spAddr stri if err != nil { return "", err } - resp, err := c.BroadcastTx(ctx, []sdk.Msg{msgGrant}, &opts.TxOption) + resp, err := c.BroadcastTx(ctx, []sdk.Msg{msgGrant}, &opts.TxOpts) if err != nil { return "", err } return resp.TxResponse.TxHash, nil } -func (c *client) UpdateSpStoragePrice(ctx context.Context, spAddr string, readPrice, storePrice sdk.Dec, freeReadQuota uint64, TxOption gnfdSdkTypes.TxOption) (string, error) { +// UpdateSpStoragePrice - Update the read price, storage price and free read quota for a particular storage provider. The sender must be the Storage provider's operator address, and SP must be STATUS_IN_SERVICE. +// +// - ctx: Context variables for the current API call. +// +// - spAddr: The HEX-encoded string of the storage provider address. +// +// - readPrice: The read price of the SP, in bnb wei per charge byte. +// +// - storePrice: The store price of the SP, in bnb wei per charge byte. +// +// - freeReadQuota: The free read quota of the SP. +// +// - TxOption: The options for customizing the transaction. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) UpdateSpStoragePrice(ctx context.Context, spAddr string, readPrice, storePrice sdk.Dec, freeReadQuota uint64, TxOption gnfdSdkTypes.TxOption) (string, error) { spAcc, err := sdk.AccAddressFromHexUnsafe(spAddr) if err != nil { return "", err @@ -247,7 +329,22 @@ func (c *client) UpdateSpStoragePrice(ctx context.Context, spAddr string, readPr return resp.TxResponse.TxHash, nil } -func (c *client) UpdateSpStatus(ctx context.Context, spAddr string, status spTypes.Status, duration int64, TxOption gnfdSdkTypes.TxOption) (string, error) { +// UpdateSpStatus - Set an SP status between STATUS_IN_SERVICE and STATUS_IN_MAINTENANCE. The sender must be the Storage provider's operator address. +// +// - ctx: Context variables for the current API call. +// +// - spAddr: The HEX-encoded string of the storage provider address. +// +// - status: The desired status. +// +// - duration: duration is requested time(in second) an SP wish to stay in maintenance mode, for setting to STATUS_IN_SERVICE, duration is set to 0. +// +// - TxOption: The options for customizing the transaction. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) UpdateSpStatus(ctx context.Context, spAddr string, status spTypes.Status, duration int64, TxOption gnfdSdkTypes.TxOption) (string, error) { spAcc, err := sdk.AccAddressFromHexUnsafe(spAddr) if err != nil { return "", err diff --git a/client/api_validator.go b/client/api_validator.go index 1b323d39..24bf2bee 100644 --- a/client/api_validator.go +++ b/client/api_validator.go @@ -17,14 +17,9 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) -type Validator interface { - // ListValidators lists all validators (if status is empty string) or validators filtered by status. - // status: - // "BOND_STATUS_UNBONDED", - // "BOND_STATUS_UNBONDING", - // "BOND_STATUS_BONDED", +// IValidatorClient - Client APIs for operating Greenfield validators and delegations. +type IValidatorClient interface { ListValidators(ctx context.Context, status string) (*stakingtypes.QueryValidatorsResponse, error) - CreateValidator(ctx context.Context, description stakingtypes.Description, commission stakingtypes.CommissionRates, selfDelegation math.Int, validatorAddress string, ed25519PubKey string, selfDelAddr string, relayerAddr string, challengerAddr string, blsKey, blsProof string, proposalDepositAmount math.Int, proposalTitle, proposalSummary, proposalMetadata string, txOption gnfdsdktypes.TxOption) (uint64, string, error) @@ -40,12 +35,59 @@ type Validator interface { ImpeachValidator(ctx context.Context, validatorAddr string, proposalDepositAmount math.Int, proposalTitle, proposalSummary, proposalMetadata string, txOption gnfdsdktypes.TxOption) (uint64, string, error) } -func (c *client) ListValidators(ctx context.Context, status string) (*stakingtypes.QueryValidatorsResponse, error) { +// ListValidators - List all validators (if status is empty string) or validators filtered by status. +// +// - ctx: Context variables for the current API call. +// +// - status: The status for filtering validators. It can be "BOND_STATUS_UNBONDED", "BOND_STATUS_UNBONDING" or "BOND_STATUS_BONDED". +// +// - ret1: The information of validators. +// +// - ret2: Return error when getting validators failed, otherwise return nil. +func (c *Client) ListValidators(ctx context.Context, status string) (*stakingtypes.QueryValidatorsResponse, error) { return c.chainClient.StakingQueryClient.Validators(ctx, &stakingtypes.QueryValidatorsRequest{Status: status}) } -// CreateValidator submits a proposal to the Greenfield for creating a validator, and it returns a proposal ID and tx hash. -func (c *client) CreateValidator(ctx context.Context, description stakingtypes.Description, commission stakingtypes.CommissionRates, +// CreateValidator - Submit a proposal to Greenfield for creating a validator, and return a proposal id and tx hash. +// +// - ctx: Context variables for the current API call. +// +// - description: The description of the validator, including name and other information. +// +// - commission: The initial commission rates to be used for creating a validator. +// +// - selfDelegation: The amount of self delegation. +// +// - validatorAddress: The address of the validator. +// +// - ed25519PubKey: The ED25519 pubkey of the validator. +// +// - selfDelAddr: The self delegation address. +// +// - relayerAddr: The address for running off-chain relayers. +// +// - challengerAddr: The address for running off-chain challenge service. +// +// - blsKey: The BLS pubkey of the validator. +// +// - blsProof: The proof of possession of the corresponding BLS private key. +// +// - proposalDepositAmount: The amount to deposit to the proposal. +// +// - proposalTitle: The title of the proposal. +// +// - proposalSummary: The summary of the proposal. +// +// - proposalMetadata: The metadata of the proposal. +// +// - txOption: The options for sending the tx. +// +// - ret1: The id of the submitted proposal. +// +// - ret2: Transaction hash return from blockchain. +// +// - ret3: Return error when create validator tx failed, otherwise return nil. +func (c *Client) CreateValidator(ctx context.Context, description stakingtypes.Description, commission stakingtypes.CommissionRates, selfDelegation math.Int, validatorAddress string, ed25519PubKey string, selfDelAddr string, relayerAddr string, challengerAddr string, blsKey, blsProof string, proposalDepositAmount math.Int, proposalTitle, proposalSummary, proposalMetadata string, txOption gnfdsdktypes.TxOption, ) (uint64, string, error) { @@ -82,12 +124,34 @@ func (c *client) CreateValidator(ctx context.Context, description stakingtypes.D if err = msg.ValidateBasic(); err != nil { return 0, "", err } - return c.SubmitProposal(ctx, []sdktypes.Msg{msg}, proposalDepositAmount, proposalTitle, proposalSummary, types.SubmitProposalOptions{Metadata: proposalMetadata, TxOption: txOption}) + return c.SubmitProposal(ctx, []sdktypes.Msg{msg}, proposalDepositAmount, proposalTitle, proposalSummary, types.SubmitProposalOptions{Metadata: proposalMetadata, TxOpts: txOption}) } -// EditValidator edits a existing validator info. -func (c *client) EditValidator(ctx context.Context, description stakingtypes.Description, - newRate *sdktypes.Dec, newMinSelfDelegation *math.Int, newRelayerAddr, newChallengerAddr, newBlsKey, blsProof string, txOption gnfdsdktypes.TxOption, +// EditValidator - Edit an existing validator's info. +// +// - ctx: Context variables for the current API call. +// +// - description: The new description of the validator, including name and other information. +// +// - newRate: The new commission rate of the validator. +// +// - newMinSelfDelegation: The value for minimal self delegation amount +// +// - newRelayerAddr: The new address for running off-chain relayers. +// +// - newChallengerAddr: The new address for running off-chain challenge service. +// +// - newBlsKey: The new BLS pubkey of the validator. +// +// - newBlsProof: The new proof of possession of the corresponding BLS private key. +// +// - txOption: The options for sending the tx. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when edit validator tx failed, otherwise return nil. +func (c *Client) EditValidator(ctx context.Context, description stakingtypes.Description, + newRate *sdktypes.Dec, newMinSelfDelegation *math.Int, newRelayerAddr, newChallengerAddr, newBlsKey, newBlsProof string, txOption gnfdsdktypes.TxOption, ) (string, error) { relayer, err := sdktypes.AccAddressFromHexUnsafe(newRelayerAddr) if err != nil { @@ -97,7 +161,7 @@ func (c *client) EditValidator(ctx context.Context, description stakingtypes.Des if err != nil { return "", err } - msg := stakingtypes.NewMsgEditValidator(c.MustGetDefaultAccount().GetAddress(), description, newRate, newMinSelfDelegation, relayer, challenger, newBlsKey, blsProof) + msg := stakingtypes.NewMsgEditValidator(c.MustGetDefaultAccount().GetAddress(), description, newRate, newMinSelfDelegation, relayer, challenger, newBlsKey, newBlsProof) resp, err := c.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) if err != nil { return "", err @@ -105,8 +169,20 @@ func (c *client) EditValidator(ctx context.Context, description stakingtypes.Des return resp.TxResponse.TxHash, nil } -// DelegateValidator makes a delegation to a validator by delegator. -func (c *client) DelegateValidator(ctx context.Context, validatorAddr string, amount math.Int, txOption gnfdsdktypes.TxOption) (string, error) { +// DelegateValidator - Make a delegation to a validator by the delegator. +// +// - ctx: Context variables for the current API call. +// +// - validatorAddr: The address of the target validator to delegate to. +// +// - amount: The amount of delegation. +// +// - txOption: The options for sending the tx. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when delegation tx failed, otherwise return nil. +func (c *Client) DelegateValidator(ctx context.Context, validatorAddr string, amount math.Int, txOption gnfdsdktypes.TxOption) (string, error) { validator, err := sdktypes.AccAddressFromHexUnsafe(validatorAddr) if err != nil { return "", err @@ -119,8 +195,22 @@ func (c *client) DelegateValidator(ctx context.Context, validatorAddr string, am return resp.TxResponse.TxHash, nil } -// BeginRedelegate delegates coins from a delegator and source validator to a destination validator -func (c *client) BeginRedelegate(ctx context.Context, validatorSrcAddr, validatorDestAddr string, amount math.Int, txOption gnfdsdktypes.TxOption) (string, error) { +// BeginRedelegate - Delegate coins from a delegator and source validator to a destination validator. +// +// - ctx: Context variables for the current API call. +// +// - validatorSrcAddr: The address of the source validator to un-delegate from. +// +// - validatorDestAddr: The address of the destination validator to delegate to. +// +// - amount: The amount of re-delegation. +// +// - txOption: The options for sending the tx. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when re-delegation tx failed, otherwise return nil. +func (c *Client) BeginRedelegate(ctx context.Context, validatorSrcAddr, validatorDestAddr string, amount math.Int, txOption gnfdsdktypes.TxOption) (string, error) { validatorSrc, err := sdktypes.AccAddressFromHexUnsafe(validatorSrcAddr) if err != nil { return "", err @@ -137,8 +227,20 @@ func (c *client) BeginRedelegate(ctx context.Context, validatorSrcAddr, validato return resp.TxResponse.TxHash, nil } -// Undelegate undelegates tokens from a validator by the delegator. -func (c *client) Undelegate(ctx context.Context, validatorAddr string, amount math.Int, txOption gnfdsdktypes.TxOption) (string, error) { +// Undelegate - Undelegate tokens from a validator by the delegator. +// +// - ctx: Context variables for the current API call. +// +// - validatorAddr: The address of the target validator to un-delegate from. +// +// - amount: The amount of un-delegation. +// +// - txOption: The options for sending the tx. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when un-delegation tx failed, otherwise return nil. +func (c *Client) Undelegate(ctx context.Context, validatorAddr string, amount math.Int, txOption gnfdsdktypes.TxOption) (string, error) { validator, err := sdktypes.AccAddressFromHexUnsafe(validatorAddr) if err != nil { return "", err @@ -151,8 +253,22 @@ func (c *client) Undelegate(ctx context.Context, validatorAddr string, amount ma return resp.TxResponse.TxHash, nil } -// CancelUnbondingDelegation cancel the unbonding delegation by delegator -func (c *client) CancelUnbondingDelegation(ctx context.Context, validatorAddr string, creationHeight int64, amount math.Int, txOption gnfdsdktypes.TxOption) (string, error) { +// CancelUnbondingDelegation - Cancel the unbonding delegation by the delegator. +// +// - ctx: Context variables for the current API call. +// +// - validatorAddr: The address of the validator to cancel the unbonding delegation. +// +// - creationHeight: The height at which the unbonding took place. +// +// - amount: The amount of un-delegation. +// +// - txOption: The options for sending the tx. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when cancel unbonding delegation tx failed, otherwise return nil. +func (c *Client) CancelUnbondingDelegation(ctx context.Context, validatorAddr string, creationHeight int64, amount math.Int, txOption gnfdsdktypes.TxOption) (string, error) { validator, err := sdktypes.AccAddressFromHexUnsafe(validatorAddr) if err != nil { return "", err @@ -165,8 +281,18 @@ func (c *client) CancelUnbondingDelegation(ctx context.Context, validatorAddr st return resp.TxResponse.TxHash, nil } -// GrantDelegationForValidator grant the gov module for proposal execution -func (c *client) GrantDelegationForValidator(ctx context.Context, delegationAmount math.Int, txOption gnfdsdktypes.TxOption) (string, error) { +// GrantDelegationForValidator - Grant the gov module for proposal execution. +// +// - ctx: Context variables for the current API call. +// +// - delegationAmount: The amount to grant. +// +// - txOption: The options for sending the tx. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when grant delegation tx failed, otherwise return nil. +func (c *Client) GrantDelegationForValidator(ctx context.Context, delegationAmount math.Int, txOption gnfdsdktypes.TxOption) (string, error) { govModule, err := c.GetModuleAccountByName(ctx, govTypes.ModuleName) if err != nil { return "", err @@ -193,8 +319,18 @@ func (c *client) GrantDelegationForValidator(ctx context.Context, delegationAmou return resp.TxResponse.TxHash, nil } -// UnJailValidator unjails the validator -func (c *client) UnJailValidator(ctx context.Context, txOption gnfdsdktypes.TxOption) (string, error) { +// UnJailValidator - Unjail a validator. +// +// The default account's address will be treated the validator address to unjail. +// +// - ctx: Context variables for the current API call. +// +// - txOption: The options for sending the tx. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when unjail validator tx failed, otherwise return nil. +func (c *Client) UnJailValidator(ctx context.Context, txOption gnfdsdktypes.TxOption) (string, error) { msg := slashingtypes.NewMsgUnjail(c.MustGetDefaultAccount().GetAddress()) resp, err := c.BroadcastTx(ctx, []sdktypes.Msg{msg}, &txOption) if err != nil { @@ -203,8 +339,26 @@ func (c *client) UnJailValidator(ctx context.Context, txOption gnfdsdktypes.TxOp return resp.TxResponse.TxHash, nil } -// ImpeachValidator impeaches a validator -func (c *client) ImpeachValidator(ctx context.Context, validatorAddr string, proposalDepositAmount math.Int, proposalTitle, proposalSummary, proposalMetadata string, txOption gnfdsdktypes.TxOption) (uint64, string, error) { +// ImpeachValidator - Impeach a validator. +// +// - ctx: Context variables for the current API call. +// +// - validatorAddr: The address of the validator to impeach. +// +// - proposalDepositAmount: The amount of BNB to deposit to the proposal. +// +// - proposalTitle: The title of the proposal. +// +// - proposalSummary: The summary of the proposal. +// +// - proposalMetadata: The metadata of the proposal. +// +// - txOption: The options for sending the tx. +// +// - ret1: Transaction hash return from blockchain. +// +// - ret2: Return error when unjail validator tx failed, otherwise return nil. +func (c *Client) ImpeachValidator(ctx context.Context, validatorAddr string, proposalDepositAmount math.Int, proposalTitle, proposalSummary, proposalMetadata string, txOption gnfdsdktypes.TxOption) (uint64, string, error) { validator, err := sdktypes.AccAddressFromHexUnsafe(validatorAddr) if err != nil { return 0, "", err @@ -215,7 +369,7 @@ func (c *client) ImpeachValidator(ctx context.Context, validatorAddr string, pro } govAccountAddr := govModule.GetAddress() msg := slashingtypes.NewMsgImpeach(validator, govAccountAddr) - return c.SubmitProposal(ctx, []sdktypes.Msg{msg}, proposalDepositAmount, proposalTitle, proposalSummary, types.SubmitProposalOptions{Metadata: proposalMetadata, TxOption: txOption}) + return c.SubmitProposal(ctx, []sdktypes.Msg{msg}, proposalDepositAmount, proposalTitle, proposalSummary, types.SubmitProposalOptions{Metadata: proposalMetadata, TxOpts: txOption}) } func pubKeyFromHex(pk string) (cryptotypes.PubKey, error) { diff --git a/client/api_virtual_group.go b/client/api_virtual_group.go index 4f363046..26d1dc60 100644 --- a/client/api_virtual_group.go +++ b/client/api_virtual_group.go @@ -6,17 +6,28 @@ import ( "github.com/bnb-chain/greenfield/x/virtualgroup/types" ) -type VirtualGroup interface { +// IVirtualGroupClient interface defines basic functions related to Virtual Group. +type IVirtualGroupClient interface { QueryVirtualGroupFamily(ctx context.Context, globalVirtualGroupFamilyID uint32) (*types.GlobalVirtualGroupFamily, error) } -func (c *client) QueryVirtualGroupFamily(ctx context.Context, globalVirtualGroupFamilyID uint32) (*types.GlobalVirtualGroupFamily, error) { +// QueryVirtualGroupFamily - Query the virtual group family by ID. +// +// Virtual group family(VGF) serve as a means of grouping global virtual groups. Each bucket must be associated with a unique global virtual group family and cannot cross families. +// +// - ctx: Context variables for the current API call. +// +// - globalVirtualGroupFamilyID: Identify the virtual group family. +// +// - ret1: The virtual group family detail. +// +// - ret2: Return error when the request failed, otherwise return nil. +func (c *Client) QueryVirtualGroupFamily(ctx context.Context, globalVirtualGroupFamilyID uint32) (*types.GlobalVirtualGroupFamily, error) { queryResponse, err := c.chainClient.GlobalVirtualGroupFamily(ctx, &types.QueryGlobalVirtualGroupFamilyRequest{ FamilyId: globalVirtualGroupFamilyID, }) if err != nil { return nil, err } - return queryResponse.GlobalVirtualGroupFamily, nil } diff --git a/client/doc.go b/client/doc.go index e6fa16b2..d12807fb 100644 --- a/client/doc.go +++ b/client/doc.go @@ -1,4 +1,4 @@ /* -Package client provides a client for interact with greenfield storage network. +Package Client provides a Client for interact with greenfield storage network. */ package client diff --git a/e2e/basesuite/suite.go b/e2e/basesuite/suite.go index ef60da54..f3ee1aeb 100644 --- a/e2e/basesuite/suite.go +++ b/e2e/basesuite/suite.go @@ -46,9 +46,9 @@ func ParseMnemonicFromFile(fileName string) string { type BaseSuite struct { suite.Suite DefaultAccount *types.Account - Client client.Client + Client client.IClient ClientContext context.Context - ChallengeClient client.Client + ChallengeClient client.IClient } // ParseValidatorMnemonic read the validator mnemonic from file diff --git a/e2e/e2e_migrate_bucket_test.go b/e2e/e2e_migrate_bucket_test.go index f44f0499..5995190b 100644 --- a/e2e/e2e_migrate_bucket_test.go +++ b/e2e/e2e_migrate_bucket_test.go @@ -4,11 +4,12 @@ import ( "bytes" "context" "fmt" - "github.com/stretchr/testify/suite" "io" "testing" "time" + "github.com/stretchr/testify/suite" + "github.com/bnb-chain/greenfield-go-sdk/e2e/basesuite" "github.com/bnb-chain/greenfield-go-sdk/types" storageTestUtil "github.com/bnb-chain/greenfield/testutil/storage" @@ -191,7 +192,7 @@ func (s *BucketMigrateTestSuite) Test_Bucket_Migrate_Simple_Case() { s.T().Logf(":Migrate Bucket DstPrimarySPID %d", destSP.GetId()) // normal no conflict send migrate bucket transaction - txhash, err := s.Client.MigrateBucket(s.ClientContext, bucketName, types.MigrateBucketOptions{TxOpts: nil, DstPrimarySPID: destSP.GetId(), IsAsyncMode: false}) + txhash, err := s.Client.MigrateBucket(s.ClientContext, bucketName, destSP.GetId(), types.MigrateBucketOptions{TxOpts: nil, IsAsyncMode: false}) s.Require().NoError(err) s.T().Logf("MigrateBucket : %s", txhash) @@ -245,7 +246,7 @@ func (s *BucketMigrateTestSuite) Test_Bucket_Migrate_Simple_Conflict_Case() { conflictSPID := objectDetail.GlobalVirtualGroup.SecondarySpIds[0] s.T().Logf(":Migrate Bucket DstPrimarySPID %d", conflictSPID) - txhash, err := s.Client.MigrateBucket(s.ClientContext, bucketName, types.MigrateBucketOptions{TxOpts: nil, DstPrimarySPID: conflictSPID, IsAsyncMode: false}) + txhash, err := s.Client.MigrateBucket(s.ClientContext, bucketName, conflictSPID, types.MigrateBucketOptions{TxOpts: nil, IsAsyncMode: false}) s.Require().NoError(err) s.T().Logf("MigrateBucket : %s", txhash) @@ -307,7 +308,7 @@ func (s *BucketMigrateTestSuite) Test_Empty_Bucket_Migrate_Simple_Case() { s.T().Logf(":Migrate Bucket DstPrimarySPID %s", destSP.String()) // normal no conflict send migrate bucket transaction - txhash, err := s.Client.MigrateBucket(s.ClientContext, bucketName, types.MigrateBucketOptions{TxOpts: nil, DstPrimarySPID: destSP.GetId(), IsAsyncMode: false}) + txhash, err := s.Client.MigrateBucket(s.ClientContext, bucketName, destSP.GetId(), types.MigrateBucketOptions{TxOpts: nil, IsAsyncMode: false}) s.Require().NoError(err) s.T().Logf("MigrateBucket : %s", txhash) diff --git a/examples/common.go b/examples/common.go index 9b1afb65..94696aef 100644 --- a/examples/common.go +++ b/examples/common.go @@ -34,7 +34,7 @@ func handleErr(err error, funcName string) { } } -func waitObjectSeal(cli client.Client, bucketName, objectName string) { +func waitObjectSeal(cli client.IClient, bucketName, objectName string) { ctx := context.Background() // wait for the object to be sealed timeout := time.After(15 * time.Second) diff --git a/examples/crosschain.go b/examples/crosschain.go index c86d7fe5..1fdaeecf 100644 --- a/examples/crosschain.go +++ b/examples/crosschain.go @@ -31,7 +31,7 @@ func main() { mirrorBucket(cli, ctx) } -func transferOut(cli client.Client, ctx context.Context) { +func transferOut(cli client.IClient, ctx context.Context) { // cross chain transfer to BSC txResp, err := cli.TransferOut(ctx, toAddress, math.NewInt(123456), gnfdSdkTypes.TxOption{}) handleErr(err, "crossChainTransfer") @@ -40,7 +40,7 @@ func transferOut(cli client.Client, ctx context.Context) { log.Printf("the tx log is %s", txResp.String()) } -func mirrorBucket(cli client.Client, ctx context.Context) { +func mirrorBucket(cli client.IClient, ctx context.Context) { // get storage providers list spLists, err := cli.ListStorageProviders(ctx, true) if err != nil { diff --git a/examples/crosschain_gov.go b/examples/crosschain_gov.go index d22fa60a..d753578f 100644 --- a/examples/crosschain_gov.go +++ b/examples/crosschain_gov.go @@ -25,7 +25,7 @@ func main() { math.NewIntWithDecimal(1000, gnfdSdkTypes.DecimalBNB), // deposit, various from different env "Change BSC contract parameter", "Change BSC contract parameter", - types.SubmitProposalOptions{TxOption: gnfdSdkTypes.TxOption{}}, + types.SubmitProposalOptions{TxOpts: gnfdSdkTypes.TxOption{}}, ) if err != nil { log.Fatalf("unable to submit proposal , %v", err) diff --git a/types/account.go b/types/account.go index 61dddf5c..0c51ec37 100644 --- a/types/account.go +++ b/types/account.go @@ -12,18 +12,27 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// TODO: Will add an AccountRegister struct to manage multi account. - +// Account indicates the user's identity information used for interaction with Greenfield. type Account struct { name string km keys.KeyManager } +// TransferDetail includes the target address and amount for token transfer. type TransferDetail struct { ToAddress string Amount math.Int } +// NewAccountFromPrivateKey - Create account instance according to private key. +// +// -name: Account name. +// +// -privKey: Private key. +// +// -ret1: The pointer of the created account instance. +// +// -ret2: Error message if the privKey is not correct, otherwise returns nil. func NewAccountFromPrivateKey(name, privKey string) (*Account, error) { km, err := keys.NewPrivateKeyManager(privKey) if err != nil { @@ -35,6 +44,15 @@ func NewAccountFromPrivateKey(name, privKey string) (*Account, error) { }, nil } +// NewAccountFromMnemonic - Create account instance according to mnemonic. +// +// -name: Account name. +// +// -mnemonic: The mnemonic string. +// +// -ret1: The pointer of the created account instance. +// +// -ret2: Error message if the mnemonic is not correct, otherwise returns nil. func NewAccountFromMnemonic(name, mnemonic string) (*Account, error) { km, err := keys.NewMnemonicKeyManager(mnemonic) if err != nil { @@ -46,8 +64,15 @@ func NewAccountFromMnemonic(name, mnemonic string) (*Account, error) { }, nil } -// TODO: return mnemonic to user - +// NewAccount - Create a random new account. +// +// -name: The account name. +// +// -ret1: The pointer of the created account instance. +// +// -ret2: The private key of the created account. +// +// -ret3: Error message. func NewAccount(name string) (*Account, string, error) { privKey := secp256k1.GenPrivKey() km, err := keys.NewPrivateKeyManager(hex.EncodeToString(privKey.Bytes())) @@ -60,6 +85,15 @@ func NewAccount(name string) (*Account, string, error) { }, hex.EncodeToString(privKey.Bytes()), nil } +// NewBlsAccount - Create a random new account with bls key pairs. +// +// -name: The account name. +// +// -ret1: The pointer of the created account instance. +// +// -ret2: The bls private key of the created account. +// +// -ret3: Error message. func NewBlsAccount(name string) (*Account, string, error) { blsPrivKey, _ := bls.RandKey() km, err := keys.NewBlsPrivateKeyManager(hex.EncodeToString(blsPrivKey.Marshal())) @@ -72,14 +106,17 @@ func NewBlsAccount(name string) (*Account, string, error) { }, hex.EncodeToString(blsPrivKey.Marshal()), nil } +// GetKeyManager - Get the key manager of the account. func (a *Account) GetKeyManager() keys.KeyManager { return a.km } +// GetAddress - Get the address of the account. func (a *Account) GetAddress() sdk.AccAddress { return a.km.GetAddr() } +// Sign - Use the account's private key to sign for the input data. func (a *Account) Sign(unsignBytes []byte) ([]byte, error) { return a.km.Sign(unsignBytes) } diff --git a/types/const.go b/types/const.go index 784bcbb5..4df933b7 100644 --- a/types/const.go +++ b/types/const.go @@ -60,7 +60,7 @@ const ( MaxDownloadTryTime = 3 DownloadBackOffDelay = time.Millisecond * 500 - // MinPartSize - minimum part size 16MiB per object after which + // MinPartSize - minimum part size 32MiB per object after which // putObject behaves internally as multipart. MinPartSize = 1024 * 1024 * 32 diff --git a/types/list.go b/types/list.go index 8c1d53a6..781f5fd1 100644 --- a/types/list.go +++ b/types/list.go @@ -11,107 +11,128 @@ type QuotaInfo struct { XMLName xml.Name `xml:"GetReadQuotaResult"` Version string `xml:"version,attr"` BucketName string `xml:"BucketName"` - BucketID string `xml:"BucketID"` - ReadQuotaSize uint64 `xml:"ReadQuotaSize"` // the bucket read quota value on chain - SPFreeReadQuotaSize uint64 `xml:"SPFreeReadQuotaSize"` // the free quota of this month - ReadConsumedSize uint64 `xml:"ReadConsumedSize"` // the consumed total read quota of this month - FreeConsumedSize uint64 `xml:"FreeConsumedSize"` // the consumed free quota + BucketID string `xml:"BucketID"` // BucketID defines the bucket read quota value on chain + ReadQuotaSize uint64 `xml:"ReadQuotaSize"` // ReadQuotaSize defines the bucket read quota value on chain + SPFreeReadQuotaSize uint64 `xml:"SPFreeReadQuotaSize"` // SPFreeReadQuotaSize defines the free quota of this month + ReadConsumedSize uint64 `xml:"ReadConsumedSize"` // ReadConsumedSize defines the consumed total read quota of this month + FreeConsumedSize uint64 `xml:"FreeConsumedSize"` // FreeConsumedSize defines the consumed free quota } +// ReadRecord indicate the download record info type ReadRecord struct { XMLName xml.Name `xml:"ReadRecord"` - ObjectName string `xml:"ObjectName"` - ObjectID string `xml:"ObjectID"` - ReadAccountAddress string `xml:"ReadAccountAddress"` - ReadTimestampUs int64 `xml:"ReadTimestampUs"` - ReadSize uint64 `xml:"ReadSize"` + ObjectName string `xml:"ObjectName"` // ObjectName The download object name + ObjectID string `xml:"ObjectID"` // ObjectID The download object id + ReadAccountAddress string `xml:"ReadAccountAddress"` // ReadAccountAddress The sender address of the download request + ReadTimestampUs int64 `xml:"ReadTimestampUs"` // ReadTimestampUs The download time stamp + ReadSize uint64 `xml:"ReadSize"` // ReadSize The download object size } // QuotaRecordInfo indicates the quota read record type QuotaRecordInfo struct { - XMLName xml.Name `xml:"GetBucketReadQuotaResult"` - Version string `xml:"version,attr"` - NextStartTimestampUs int64 `xml:"NextStartTimestampUs"` - ReadRecords []ReadRecord `xml:"ReadRecord"` + XMLName xml.Name `xml:"GetBucketReadQuotaResult"` + Version string `xml:"version,attr"` // The Version defines version info + // When using ListBucketReadRecord to list items, if the returned results do not cover all items, the NextStartTimestampUs will be returned to indicate the timestamp of the current traversal progress. + // When you call the ListBucketReadRecord again, you can set opt.StartTimeStamp to this timestamp. + NextStartTimestampUs int64 `xml:"NextStartTimestampUs"` + // ReadRecords defines the result record list. + ReadRecords []ReadRecord `xml:"ReadRecord"` } // UploadProgress indicates the progress info of uploading object type UploadProgress struct { XMLName xml.Name `xml:"QueryUploadProgress"` - Version string `xml:"version,attr"` - ProgressDescription string `xml:"ProgressDescription"` - ErrorDescription string `xml:"ErrorDescription"` + Version string `xml:"version,attr"` // Version defines version info + ProgressDescription string `xml:"ProgressDescription"` // ProgressDescription defines a string message representing the upload progress. + ErrorDescription string `xml:"ErrorDescription"` // ErrorDescription defines a string message representing an upload error exception. } // UploadOffset indicates the offset of resumable uploading object type UploadOffset struct { XMLName xml.Name `xml:"QueryResumeOffset"` - Version string `xml:"version,attr"` - Offset uint64 `xml:"Offset"` + Version string `xml:"version,attr"` // Version defines version info + Offset uint64 `xml:"Offset"` // Offset defines the offset info of resumable uploading object } +// ListObjectsResult indicates the result of listObjects API. type ListObjectsResult struct { - // objects defines the list of object - Objects []*ObjectMeta `xml:"Objects"` - KeyCount string `xml:"KeyCount"` - MaxKeys string `xml:"MaxKeys"` - IsTruncated bool `xml:"IsTruncated"` - NextContinuationToken string `xml:"NextContinuationToken"` - Name string `xml:"Name"` - Prefix string `xml:"Prefix"` - Delimiter string `xml:"Delimiter"` - CommonPrefixes []string `xml:"CommonPrefixes"` - ContinuationToken string `xml:"ContinuationToken"` + // Objects defines the list of object + Objects []*ObjectMeta `xml:"Objects"` + // KeyCount is the number of keys returned with this request + KeyCount string `xml:"KeyCount"` + // MaxKeys sets the maximum number of keys returned to the response + MaxKeys string `xml:"MaxKeys"` + // IsTruncated set to false if all of the results were returned. set to true if more keys are available to return + IsTruncated bool `xml:"IsTruncated"` + // NextContinuationToken is sent when is_truncated is true, which means there are more keys in the bucket that can be listed + NextContinuationToken string `xml:"NextContinuationToken"` + // Name defines the name of the bucket + Name string `xml:"Name"` + // Prefix is the prefix used during the query + Prefix string `xml:"Prefix"` + // Delimiter is the delimiter used during the query + Delimiter string `xml:"Delimiter"` + // CommonPrefixes defines a list of strings representing common prefixes. common_prefixes are those parts of object key names that fall between the specified delimiters + CommonPrefixes []string `xml:"CommonPrefixes"` + // ContinuationToken is the continuation token used during the query + ContinuationToken string `xml:"ContinuationToken"` } +// ListBucketsResult defines the response of list bucekts response type ListBucketsResult struct { - // buckets defines the list of bucket + // Buckets defines the list of bucket Buckets []*BucketMetaWithVGF `xml:"Buckets"` } +// ListBucketsByPaymentAccountResult defines the response of list buckets by payment account type ListBucketsByPaymentAccountResult struct { - // buckets defines the list of bucket + // Buckets defines the list of bucket Buckets []*BucketMeta `xml:"Buckets"` } +// ListUserPaymentAccountsResult defines the response of list user payment accounts type ListUserPaymentAccountsResult struct { // PaymentAccount defines the list of payment accounts PaymentAccounts []*PaymentAccounts `xml:"PaymentAccounts"` } +// ListGroupsResult define the response of list groups type ListGroupsResult struct { - // groups defines the response of group list + // Groups defines the response of group list Groups []*GroupMeta `json:"Groups"` - // count defines total groups amount + // Count defines total groups amount Count int64 `xml:"Count"` } +// GroupMembersResult indicates the response of ListGroupMembers type GroupMembersResult struct { - // groups defines the response of group member list + // Groups defines the response of group member list Groups []*GroupMembers `xml:"Groups"` } +// GroupsResult indicates a list of group members type GroupsResult struct { - // groups defines the response of group member list + // Groups defines the response of group member list Groups []*GroupMembers `xml:"Groups"` } +// GroupMembers indicates the group member info type GroupMembers struct { - // group defines the basic group info + // Group defines the basic group info Group *GroupInfo `xml:"Group"` - // operator defines operator address of group + // Operator defines operator address of group Operator string `xml:"Operator"` - // create_at defines the block number when the group created + // CreateAt defines the block number when the group created CreateAt int64 `xml:"CreateAt"` - // create_time defines the timestamp when the group created + // CreateTime defines the timestamp when the group created CreateTime int64 `xml:"CreateTime"` - // update_at defines the block number when the group updated + // UpdateAt defines the block number when the group updated UpdateAt int64 `xml:"UpdateAt"` - // update_time defines the timestamp when the group updated + // UpdateTime defines the timestamp when the group updated UpdateTime int64 `xml:"UpdateTime"` - // removed defines the group is deleted or not + // Removed defines the group is deleted or not Removed bool `xml:"Removed"` - // the address of account + // AccountID defines the address of account AccountID string `xml:"AccountId"` // ExpirationTime is the user expiration time for this group ExpirationTime string `xml:"ExpirationTime"` @@ -119,25 +140,25 @@ type GroupMembers struct { // ObjectMeta is the structure for metadata service user object type ObjectMeta struct { - // object_info defines the information of the object. + // ObjectInfo defines the information of the object. ObjectInfo *ObjectInfo `xml:"ObjectInfo"` - // locked_balance defines locked balance of object + // LockedBalance defines locked balance of object LockedBalance string `xml:"LockedBalance"` - // removed defines the object is deleted or not + // Removed defines the object is deleted or not Removed bool `xml:"Removed"` - // update_at defines the block number when the object updated + // UpdateAt defines the block number when the object updated UpdateAt int64 `xml:"UpdateAt"` - // delete_at defines the block number when the object deleted + // DeleteAt defines the block number when the object deleted DeleteAt int64 `xml:"DeleteAt"` - // delete_reason defines the deleted reason of object + // DeleteReason defines the deleted reason of object DeleteReason string `xml:"DeleteReason"` - // operator defines the operator address of object + // Operator defines the operator address of object Operator string `xml:"Operator"` - // create_tx_hash defines the creation transaction hash of object + // CreateTxHash defines the creation transaction hash of object CreateTxHash string `xml:"CreateTxHash"` - // update_tx_hash defines the update transaction hash of object + // UpdateTxHash defines the update transaction hash of object UpdateTxHash string `xml:"UpdateTxHash"` - // seal_tx_hash defines the sealed transaction hash of object + // SealTxHash defines the sealed transaction hash of object SealTxHash string `xml:"SealTxHash"` } @@ -155,122 +176,124 @@ type ObjectAndBucketIDs struct { // GlobalVirtualGroupFamily serve as a means of grouping global virtual groups. // Each bucket must be associated with a unique global virtual group family and cannot cross families. type GlobalVirtualGroupFamily struct { - // id is the identifier of the global virtual group family. + // Id is the identifier of the global virtual group family. Id uint32 `xml:"Id"` - // primary_sp_id is the id of primary sp + // PrimarySpId is the id of primary sp PrimarySpId uint32 `xml:"PrimarySpId"` - // global_virtual_group_ids is a list of identifiers of the global virtual groups associated with the family. + // GlobalVirtualGroupIds is a list of identifiers of the global virtual groups associated with the family. GlobalVirtualGroupIds []uint32 `xml:"GlobalVirtualGroupIds"` - // virtual_payment_address is the payment address associated with the global virtual group family. + // VirtualPaymentAddress is the payment address associated with the global virtual group family. VirtualPaymentAddress string `xml:"VirtualPaymentAddress"` } // BucketMetaWithVGF BucketMeta is the structure for metadata service user bucket type BucketMetaWithVGF struct { - // bucket_info defines the information of the bucket. + // BucketInfo defines the information of the bucket. BucketInfo *BucketInfo `xml:"BucketInfo"` - // removed defines the bucket is deleted or not + // Removed defines the bucket is deleted or not Removed bool `xml:"Removed"` - // delete_at defines the block number when the bucket deleted. + // DeleteAt defines the block number when the bucket deleted. DeleteAt int64 `xml:"DeleteAt"` - // delete_reason defines the deleted reason of bucket + // DeleteReason defines the deleted reason of bucket DeleteReason string `xml:"DeleteReason"` - // operator defines the operator address of bucket + // Operator defines the operator address of bucket Operator string `xml:"Operator"` - // create_tx_hash defines the creation transaction hash of bucket + // CreateTxHash defines the creation transaction hash of bucket CreateTxHash string `xml:"CreateTxHash"` - // update_tx_hash defines the update transaction hash of bucket + // UpdateTxHash defines the update transaction hash of bucket UpdateTxHash string `xml:"UpdateTxHash"` - // update_at defines the block number when the bucket updated + // UpdateAt defines the block number when the bucket updated UpdateAt int64 `xml:"UpdateAt"` - // update_time defines the block number when the bucket updated + // UpdateTime defines the block number when the bucket updated UpdateTime int64 `xml:"UpdateTime"` - // GlobalVirtualGroupFamily serve as a means of grouping global virtual groups. + // Vgf serve as a means of grouping global virtual groups. Vgf *GlobalVirtualGroupFamily `xml:"Vgf"` } // BucketMeta is the structure for metadata service user bucket type BucketMeta struct { - // bucket_info defines the information of the bucket. + // BucketInfo defines the information of the bucket. BucketInfo *BucketInfo `xml:"BucketInfo"` - // removed defines the bucket is deleted or not + // Removed defines the bucket is deleted or not Removed bool `xml:"Removed"` - // delete_at defines the block number when the bucket deleted. + // DeleteAt defines the block number when the bucket deleted. DeleteAt int64 `xml:"DeleteAt"` - // delete_reason defines the deleted reason of bucket + // DeleteReason defines the deleted reason of bucket DeleteReason string `xml:"DeleteReason"` - // operator defines the operator address of bucket + // Operator defines the operator address of bucket Operator string `xml:"Operator"` - // create_tx_hash defines the creation transaction hash of bucket + // CreateTxHash defines the creation transaction hash of bucket CreateTxHash string `xml:"CreateTxHash"` - // update_tx_hash defines the update transaction hash of bucket + // UpdateTxHash defines the update transaction hash of bucket UpdateTxHash string `xml:"UpdateTxHash"` - // update_at defines the block number when the bucket updated + // UpdateAt defines the block number when the bucket updated UpdateAt int64 `xml:"UpdateAt"` - // update_time defines the block number when the bucket updated + // UpdateTime defines the block number when the bucket updated UpdateTime int64 `xml:"UpdateTime"` } // ObjectInfo differ from ObjectInfo in greenfield as it adds uint64/int64 unmarshal guide in json part type ObjectInfo struct { + // Owner defines the object owner Owner string `xml:"Owner"` - // bucket_name is the name of the bucket + // BucketName is the name of the bucket BucketName string `xml:"BucketName"` - // object_name is the name of object + // ObjectName is the name of object ObjectName string `xml:"ObjectName"` - // id is the unique identifier of object - Id uint64 `xml:"Id"` + // Id is the unique identifier of object + Id uint64 `xml:"Id"` + // LocalVirtualGroupId defines the lvg id of object LocalVirtualGroupId uint32 `xml:"LocalVirtualGroupId"` - // payloadSize is the total size of the object payload + // PayloadSize is the total size of the object payload PayloadSize uint64 `xml:"PayloadSize"` - // visibility defines the highest permissions for object. When an object is public, everyone can access it. + // Visibility defines the highest permissions for object. When an object is public, everyone can access it. Visibility storageType.VisibilityType `xml:"Visibility"` - // content_type define the format of the object which should be a standard MIME type. + // ContentType define the format of the object which should be a standard MIME type. ContentType string `xml:"ContentType"` - // create_at define the block number when the object created + // CreateAt define the block number when the object created CreateAt int64 `xml:"CreateAt"` - // object_status define the upload status of the object. + // ObjectStatus define the upload status of the object. ObjectStatus storageType.ObjectStatus `xml:"ObjectStatus"` - // redundancy_type define the type of the redundancy which can be multi-replication or EC. + // RedundancyType define the type of the redundancy which can be multi-replication or EC. RedundancyType storageType.RedundancyType `xml:"RedundancyType"` - // source_type define the source of the object. + // SourceType define the source of the object. SourceType storageType.SourceType `xml:"SourceType"` - // checksums define the root hash of the pieces which stored in a SP. + // Checksums define the root hash of the pieces which stored in a SP. Checksums [][]byte `xml:"Checksums"` } // BucketInfo differ from BucketInfo in greenfield as it adds uint64/int64 unmarshal guide in json part type BucketInfo struct { - // owner is the account address of bucket creator, it is also the bucket owner. + // Owner is the account address of bucket creator, it is also the bucket owner. Owner string `xml:"Owner"` - // bucket_name is a globally unique name of bucket + // BucketName is a globally unique name of bucket BucketName string `xml:"BucketName"` - // visibility defines the highest permissions for bucket. When a bucket is public, everyone can get storage objects in it. + // Visibility defines the highest permissions for bucket. When a bucket is public, everyone can get storage objects in it. Visibility storageType.VisibilityType `xml:"Visibility"` - // id is the unique identification for bucket. + // Id is the unique identification for bucket. Id uint64 `xml:"Id"` - // source_type defines which chain the user should send the bucket management transactions to + // SourceType defines which chain the user should send the bucket management transactions to SourceType storageType.SourceType `xml:"SourceType"` - // create_at define the block number when the bucket created + // CreateAt define the block number when the bucket created CreateAt int64 `xml:"CreateAt"` - // payment_address is the address of the payment account + // PaymentAddress is the address of the payment account PaymentAddress string `xml:"PaymentAddress"` - // primary_sp_id is the unique id of the primary sp. Objects belongs to this bucket will never + // PrimarySpId is the unique id of the primary sp. Objects belongs to this bucket will never // leave this SP, unless you explicitly shift them to another SP. PrimarySpId uint32 `xml:"PrimarySpId"` - // global_virtual_group_family_id defines the unique id of gvg family + // GlobalVirtualGroupFamilyId defines the unique id of gvg family GlobalVirtualGroupFamilyId uint32 `xml:"GlobalVirtualGroupFamilyId"` - // charged_read_quota defines the traffic quota for read in bytes per month. + // ChargedReadQuota defines the traffic quota for read in bytes per month. // The available read data for each user is the sum of the free read data provided by SP and // the ChargeReadQuota specified here. ChargedReadQuota uint64 `xml:"ChargedReadQuota"` - // bucket_status define the status of the bucket. + // BucketStatus define the status of the bucket. BucketStatus storageType.BucketStatus `xml:"BucketStatus"` } // ListBucketsByBucketIDResponse is response type for the ListBucketsByBucketID type ListBucketsByBucketIDResponse struct { - // buckets defines the information of a bucket map + // Buckets defines the information of a bucket map Buckets map[uint64]*BucketMeta `xml:"Buckets"` } @@ -282,35 +305,35 @@ type ListGroupsByGroupIDResponse struct { // GroupMeta is the structure for group information type GroupMeta struct { - // group defines the basic group info + // Group defines the basic group info Group *GroupInfo `xml:"Group"` // NumberOfMembers defines how many members in this group NumberOfMembers int64 `xml:"NumberOfMembers"` - // operator defines operator address of group + // Operator defines operator address of group Operator string `xml:"Operator"` - // create_at defines the block number when the group created + // CreateAt defines the block number when the group created CreateAt int64 `xml:"CreateAt"` - // create_time defines the timestamp when the group created + // CreateTime defines the timestamp when the group created CreateTime int64 `xml:"CreateTime"` - // update_at defines the block number when the group updated + // UpdateAt defines the block number when the group updated UpdateAt int64 `xml:"UpdateAt"` - // update_time defines the timestamp when the group updated + // UpdateTime defines the timestamp when the group updated UpdateTime int64 `xml:"UpdateTime"` - // removed defines the group is deleted or not + // Removed defines the group is deleted or not Removed bool `xml:"Removed"` } // GroupInfo differ from GroupInfo in greenfield as it adds uint64/int64 unmarshal guide in json part type GroupInfo struct { - // owner is the owner of the group. It can not changed once it created. + // Owner is the owner of the group. It can not changed once it created. Owner string `xml:"Owner"` - // group_name is the name of group which is unique under an account. + // GroupName is the name of group which is unique under an account. GroupName string `xml:"GroupName"` - // source_type + // SourceType SourceType storageType.SourceType `xml:"SourceType"` - // id is the unique identifier of group + // Id is the unique identifier of group Id uint64 `xml:"Id"` - // extra is used to store extra info for the group + // Extra is used to store extra info for the group Extra string `xml:"Extra"` } @@ -323,27 +346,27 @@ type PaymentAccounts struct { // StreamRecord defines Record of a stream account type StreamRecord struct { - // account address + // Account address Account string `xml:"Account"` - // latest update timestamp of the stream record + // CrudTimestamp defines latest update timestamp of the stream record CrudTimestamp int64 `xml:"CrudTimestamp"` - // The per-second rate that an account's balance is changing. + // NetflowRate defines The per-second rate that an account's balance is changing. // It is the sum of the account's inbound and outbound flow rates. NetflowRate int64 `xml:"NetflowRate"` - // The balance of the stream account at the latest CRUD timestamp. + // StaticBalance defines The balance of the stream account at the latest CRUD timestamp. StaticBalance int64 `xml:"StaticBalance"` - // reserved balance of the stream account + // BufferBalance defines reserved balance of the stream account // If the netflow rate is negative, the reserved balance is `netflow_rate * reserve_time` BufferBalance int64 `xml:"BufferBalance"` - // the locked balance of the stream account after it puts a new object and before the object is sealed + // LockBalance defines the locked balance of the stream account after it puts a new object and before the object is sealed LockBalance int64 `xml:"LockBalance"` - // the status of the stream account + // Status defines the status of the stream account Status int32 `xml:"Status"` - // the unix timestamp when the stream account will be settled + // SettleTimestamp defines the unix timestamp when the stream account will be settled SettleTimestamp int64 `xml:"SettleTimestamp"` - // the count of its out flows + // OutFlowCount defines the count of its out flows OutFlowCount uint64 `xml:"OutFlowCount"` - // the frozen netflow rate, which is used when resuming stream account + // FrozenNetflowRate defines the frozen netflow rate, which is used when resuming stream account FrozenNetflowRate int64 `xml:"FrozenNetflowRate"` } @@ -361,23 +384,25 @@ type PaymentAccount struct { UpdateTime int64 `xml:"UpdateTime"` } +// ListObjectPoliciesResponse define the response of list object policies type ListObjectPoliciesResponse struct { Policies []*PolicyMeta `xml:"Policies"` } +// PolicyMeta defines the policy info type PolicyMeta struct { - // principal_type defines the type of principal + // PrincipalType defines the type of principal PrincipalType int32 `xml:"PrincipalType"` - // principal_value defines the value of principal + // PrincipalValue defines the value of principal PrincipalValue string `xml:"PrincipalValue"` - // resource_type defines the type of resource that grants permission for + // ResourceType defines the type of resource that grants permission for ResourceType int32 `xml:"ResourceType"` - // resource_id defines the bucket/object/group id of the resource that grants permission for + // ResourceId defines the bucket/object/group id of the resource that grants permission for ResourceId string `xml:"ResourceId"` - // create_timestamp defines the create time of permission + // CreateTimestamp defines the create time of permission CreateTimestamp int64 `xml:"CreateTimestamp"` - // update_timestamp defines the update time of permission + // UpdateTimestamp defines the update time of permission UpdateTimestamp int64 `xml:"UpdateTimestamp"` - // expiration_time defines the expiration time of permission + // ExpirationTime defines the expiration time of permission ExpirationTime int64 `xml:"ExpirationTime"` } diff --git a/types/option.go b/types/option.go index 761d6be3..85a29e8d 100644 --- a/types/option.go +++ b/types/option.go @@ -6,151 +6,161 @@ import ( "cosmossdk.io/math" gnfdsdktypes "github.com/bnb-chain/greenfield/sdk/types" - "github.com/bnb-chain/greenfield/types/common" storageTypes "github.com/bnb-chain/greenfield/x/storage/types" sdk "github.com/cosmos/cosmos-sdk/types" ) -// CreateBucketOptions indicates the meta to construct createBucket msg of storage module -// PaymentAddress indicates the HEX-encoded string of the payment address +// CreateBucketOptions indicates the metadata to construct `CreateBucket` msg of storage module. type CreateBucketOptions struct { - Visibility storageTypes.VisibilityType - TxOpts *gnfdsdktypes.TxOption - PaymentAddress string - ChargedQuota uint64 - IsAsyncMode bool // indicate whether to create the bucket in asynchronous mode + Visibility storageTypes.VisibilityType // Visibility defines the bucket public status. + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. + PaymentAddress string // PaymentAddress indicates the HEX-encoded string of the payment address. + ChargedQuota uint64 // ChargedQuota defines the read data that users are charged for, measured in bytes. + IsAsyncMode bool // indicate whether to create the bucket in asynchronous mode. } +// MigrateBucketOptions indicates the metadata to construct `MigrateBucket` msg of storage module. type MigrateBucketOptions struct { - DstPrimarySPID uint32 - DstPrimarySPApproval common.Approval - TxOpts *gnfdsdktypes.TxOption - IsAsyncMode bool // indicate whether to create the bucket in asynchronous mode + TxOpts *gnfdsdktypes.TxOption + IsAsyncMode bool // indicate whether to create the bucket in asynchronous mode } +// CancelMigrateBucketOptions indicates the metadata to construct `CancelMigrateBucket` msg of storage module. type CancelMigrateBucketOptions struct { - ProposalDepositAmount math.Int // wei BNB - - ProposalTitle string - ProposalSummary string - ProposalMetaData string - TxOpts gnfdsdktypes.TxOption - IsAsyncMode bool // indicate whether to create the bucket in asynchronous mode + ProposalDepositAmount math.Int // ProposalDepositAmount defines the amount in wei BNB. + ProposalTitle string // ProposalTitle defines the title for proposal. + ProposalSummary string // ProposalSummary defines the summary for proposal. + ProposalMetadata string // ProposalMetadata defines the metadata for proposal. + TxOpts gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. + IsAsyncMode bool // IsAsyncMode indicates whether to create the bucket in asynchronous mode. } +// VoteProposalOptions indicates the metadata to construct `VoteProposal` msg. type VoteProposalOptions struct { - Metadata string - TxOption gnfdsdktypes.TxOption + Metadata string // Metadata defines the metadata to be submitted along with the vote. + TxOpts gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. } +// SubmitProposalOptions indicates the metadata to construct `SubmitProposal` msg. type SubmitProposalOptions struct { - Metadata string - TxOption gnfdsdktypes.TxOption + Metadata string // metadata efines the metadata to be submitted along with the proposal. + TxOpts gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. } +// CreateStorageProviderOptions indicates the metadata to construct `CreateStorageProvider` msg. type CreateStorageProviderOptions struct { - ReadPrice sdk.Dec - FreeReadQuota uint64 - StorePrice sdk.Dec - ProposalDepositAmount math.Int // wei BNB + ReadPrice sdk.Dec // ReadPrice defines the storage provider's read price, in bnb wei per charge byte. + FreeReadQuota uint64 // FreeReadQuota defines the free read quota of the SP. + StorePrice sdk.Dec // StorePrice defines the store price of the SP, in bnb wei per charge byte. + ProposalDepositAmount math.Int // ProposalDepositAmount defines the amount needed for a proposal. ProposalTitle string ProposalSummary string ProposalMetaData string - TxOption gnfdsdktypes.TxOption + TxOpts gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. } +// GrantDepositForStorageProviderOptions indicates the metadata to construct `Grant` msg. type GrantDepositForStorageProviderOptions struct { - Expiration *time.Time - TxOption gnfdsdktypes.TxOption + Expiration *time.Time // Expiration defines the expiration time of grant. + TxOpts gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. } +// DeleteBucketOption indicates the metadata to construct `DeleteBucket` msg. type DeleteBucketOption struct { - TxOpts *gnfdsdktypes.TxOption + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. } +// UpdatePaymentOption indicates the metadata to construct `UpdateBucketInfo` msg. type UpdatePaymentOption struct { - TxOpts *gnfdsdktypes.TxOption + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. } -// UpdateBucketOptions indicates the meta to construct updateBucket msg of storage module -// PaymentAddress indicates the HEX-encoded string of the payment address +// UpdateBucketOptions indicates the metadata to construct `UpdateBucketInfo` msg of storage module. type UpdateBucketOptions struct { - Visibility storageTypes.VisibilityType - TxOpts *gnfdsdktypes.TxOption - PaymentAddress string - ChargedQuota *uint64 + Visibility storageTypes.VisibilityType // Visibility defines the bucket public status. + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. + PaymentAddress string // PaymentAddress defines the HEX-encoded string of the payment address. + ChargedQuota *uint64 // ChargedQuota defines the read data that users are charged for, measured in bytes. } +// UpdateObjectOption indicates the metadata to construct `UpdateObjectInfo` msg of storage module. type UpdateObjectOption struct { - TxOpts *gnfdsdktypes.TxOption + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. } +// CancelCreateOption indicates the metadata to construct `CancelCreateObject` msg of storage module. type CancelCreateOption struct { - TxOpts *gnfdsdktypes.TxOption + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. } +// BuyQuotaOption indicates the metadata to construct `UpdateBucketInfo` msg of storage module. type BuyQuotaOption struct { - TxOpts *gnfdsdktypes.TxOption + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. } +// UpdateVisibilityOption indicates the metadata to construct `UpdateBucketInfo` msg of storage module. type UpdateVisibilityOption struct { - TxOpts *gnfdsdktypes.TxOption + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. } +// DeleteObjectOption indicates the metadata to construct `DeleteObject` msg of storage module. type DeleteObjectOption struct { - TxOpts *gnfdsdktypes.TxOption + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. } +// DeleteGroupOption indicates the metadata to construct `DeleteGroup` msg of storage module. type DeleteGroupOption struct { - TxOpts *gnfdsdktypes.TxOption + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. } -// CreateObjectOptions indicates the metadata to construct `createObject` message of storage module +// CreateObjectOptions - indicates the metadata to construct `createObject` message of storage module. type CreateObjectOptions struct { - Visibility storageTypes.VisibilityType - TxOpts *gnfdsdktypes.TxOption - SecondarySPAccs []sdk.AccAddress - ContentType string - IsReplicaType bool // indicates whether the object use REDUNDANCY_REPLICA_TYPE - IsAsyncMode bool // indicate whether to create the object in asynchronous mode - IsSerialComputeMode bool // indicate whether to compute integrity hash in serial way or parallel way when creating object + Visibility storageTypes.VisibilityType // Visibility defines the bucket public status. + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. + SecondarySPAccs []sdk.AccAddress // SecondarySPAccs indicates a list of secondary Storage Provider's addresses. + ContentType string // ContentType defines the content type of object. + IsReplicaType bool // IsReplicaType indicates whether the object uses REDUNDANCY_REPLICA_TYPE. + IsAsyncMode bool // IsAsyncMode indicate whether to create the object in asynchronous mode. + IsSerialComputeMode bool // IsSerialComputeMode indicate whether to compute integrity hash in serial way or parallel way when creating an object. } -// CreateGroupOptions indicates the meta to construct createGroup msg +// CreateGroupOptions indicates the metadata to construct `CreateGroup` msg. type CreateGroupOptions struct { - Extra string - TxOpts *gnfdsdktypes.TxOption + Extra string // Extra defines the extra meta for a group. + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. } -// UpdateGroupMemberOption indicates the info to update group member +// UpdateGroupMemberOption indicates the metadata to construct `UpdateGroupMembers` msg. type UpdateGroupMemberOption struct { - TxOpts *gnfdsdktypes.TxOption - ExpirationTime []*time.Time + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. + ExpirationTime []*time.Time // ExpirationTime defines a list of expiration time for each group member to be updated. } +// LeaveGroupOption indicates the metadata to construct `LeaveGroup` msg of storage module. type LeaveGroupOption struct { - TxOpts *gnfdsdktypes.TxOption + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. } -// RenewGroupMemberOption indicates the info to update group member +// RenewGroupMemberOption indicates the metadata to construct `RenewGroupMember` msg of storage module. type RenewGroupMemberOption struct { - TxOpts *gnfdsdktypes.TxOption - ExpirationTime []*time.Time + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. + ExpirationTime []*time.Time // ExpirationTime defines a list of expiration time for each group member to be updated. } -// ComputeHashOptions indicates the metadata of redundancy strategy +// ComputeHashOptions indicates the metadata of redundancy strategy. type ComputeHashOptions struct { SegmentSize uint64 DataShards uint32 ParityShards uint32 } -// ListReadRecordOptions indicates the start timestamp of the return read quota record +// ListReadRecordOptions contains the options for `ListBucketReadRecord` API. type ListReadRecordOptions struct { - StartTimeStamp int64 + StartTimeStamp int64 // StartTimeStamp indicates the start timestamp of the return read quota record. MaxRecords int } +// ListObjectsOptions contains the options for `ListObjects` API. type ListObjectsOptions struct { // ShowRemovedObject determines whether to include objects that have been marked as removed in the list. // If set to false, these objects will be skipped. @@ -179,17 +189,19 @@ type ListObjectsOptions struct { // If not specified, the default value is 50. // The maximum limit for returning objects is 1000 MaxKeys uint64 - Endpoint string // indicates the endpoint of sp - SPAddress string // indicates the HEX-encoded string of the sp address to be challenged + Endpoint string // indicates the endpoint of sp. + SPAddress string // indicates the HEX-encoded string of the sp address to be challenged. } +// PutPolicyOption indicates the metadata to construct `PutPolicy` msg of storage module. type PutPolicyOption struct { - TxOpts *gnfdsdktypes.TxOption - PolicyExpireTime *time.Time + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. + PolicyExpireTime *time.Time // PolicyExpireTime defines the expiration timestamp of policy. } +// DeletePolicyOption indicates the metadata to construct `DeletePolicy` msg of storage module. type DeletePolicyOption struct { - TxOpts *gnfdsdktypes.TxOption + TxOpts *gnfdsdktypes.TxOption // TxOpts defines the options to customize a transaction. } type NewStatementOptions struct { @@ -197,86 +209,76 @@ type NewStatementOptions struct { LimitSize uint64 } -type ApproveBucketOptions struct { - IsPublic bool - PaymentAddress sdk.AccAddress -} - -type ApproveObjectOptions struct { - IsPublic bool - SecondarySPAccs []sdk.AccAddress -} - +// PutObjectOptions indicates the options for uploading an object to Storage Provider. type PutObjectOptions struct { - ContentType string - TxnHash string - DisableResumable bool + ContentType string // ContentType indicates the content type of object. + TxnHash string // TxnHash indicates the transaction hash creating the object meta on chain. + DisableResumable bool // DisableResumable indicates whether upload the object to Storage Provider via resumable upload. PartSize uint64 } -// GetObjectOptions contains the options of getObject +// GetObjectOptions contains the options for `GetObject` API. type GetObjectOptions struct { - Range string `url:"-" header:"Range,omitempty"` // support for downloading partial data - SupportRecovery bool // support recover data from secondary SPs if primary SP not in service - SupportResumable bool // support resumable download. Resumable downloads refer to the capability of resuming interrupted or incomplete downloads from the point where they were paused or disrupted. - PartSize uint64 // indicate the resumable download's part size, download a large file in multiple parts. The part size is an integer multiple of the segment size. + Range string `url:"-" header:"Range,omitempty"` // Range support for downloading partial data. + SupportRecovery bool // SupportRecovery support recover data from secondary SPs if primary SP not in service. + SupportResumable bool // SupportResumable support resumable download. Resumable downloads refer to the capability of resuming interrupted or incomplete downloads from the point where they were paused or disrupted. + PartSize uint64 // PartSize indicate the resumable download's part size, download a large file in multiple parts. The part size is an integer multiple of the segment size. } +// GetChallengeInfoOptions contains the options for querying challenge data. type GetChallengeInfoOptions struct { - Endpoint string // indicates the endpoint of sp - SPAddress string // indicates the HEX-encoded string of the sp address to be challenged + Endpoint string // Endpoint indicates the endpoint of sp + SPAddress string // SPAddress indicates the HEX-encoded string of the sp address to be challenged. } +// GetSecondaryPieceOptions contains the options for `GetSecondaryPiece` API. type GetSecondaryPieceOptions struct { - Endpoint string // indicates the endpoint of sp - SPAddress string // indicates the HEX-encoded string of the sp address to be challenged + Endpoint string // Endpoint indicates the endpoint of sp. + SPAddress string // SPAddress indicates the HEX-encoded string of the sp address to be challenged. } +// ListGroupsOptions contains the options for `ListGroups` API. type ListGroupsOptions struct { - SourceType string + SourceType string // SourceType indicates the source type of group. Limit int64 Offset int64 - Endpoint string // indicates the endpoint of sp - SPAddress string // indicates the HEX-encoded string of the sp address to be challenged + Endpoint string // Endpoint indicates the endpoint of sp. + SPAddress string // SPAddress indicates the HEX-encoded string of the sp address to be challenged. } +// GroupMembersPaginationOptions contains the options for `ListGroupMembers` API. type GroupMembersPaginationOptions struct { // Limit determines the number of group data records to be returned. // If the limit is set to 0, it will default to 50. // If the limit exceeds 1000, only 1000 records will be returned. - Limit int64 - // StartAfter is used to input the user's account address for pagination purposes - StartAfter string - Endpoint string // indicates the endpoint of sp - SPAddress string // indicates the HEX-encoded string of the sp address to be challenged + Limit int64 + StartAfter string // StartAfter is used to input the user's account address for pagination purposes. + Endpoint string // indicates the endpoint of sp. + SPAddress string // indicates the HEX-encoded string of the sp address to be challenged. } +// GroupsOwnerPaginationOptions contains the options for `ListGroupsByOwner` API. type GroupsOwnerPaginationOptions struct { // Limit determines the number of group data records to be returned. // If the limit is set to 0, it will default to 50. // If the limit exceeds 1000, only 1000 records will be returned. - Limit int64 - // StartAfter is used to input the group id for pagination purposes - StartAfter string - // Owner defines the owner account address of groups - // if owner is set to "", it will default to current user address - Owner string - Endpoint string // indicates the endpoint of sp - SPAddress string // indicates the HEX-encoded string of the sp address to be challenged + Limit int64 + StartAfter string // StartAfter is used to input the group id for pagination purposes. + Owner string // Owner defines the owner account address of groups, if owner is set to "", it will default to current user address. + Endpoint string // Endpoint indicates the endpoint of sp. + SPAddress string // SPAddress indicates the HEX-encoded string of the sp address to be challenged. } +// GroupsPaginationOptions contains the options for `ListGroupsByAccount` API. type GroupsPaginationOptions struct { // Limit determines the number of group data records to be returned. // If the limit is set to 0, it will default to 50. // If the limit exceeds 1000, only 1000 records will be returned. - Limit int64 - // StartAfter is used to input the group id for pagination purposes - StartAfter string - // Account defines the user account address - // if account is set to "", it will default to current user address - Account string - Endpoint string // indicates the endpoint of sp - SPAddress string // indicates the HEX-encoded string of the sp address to be challenged + Limit int64 + StartAfter string // StartAfter is used to input the group id for pagination purposes. + Account string // Account defines the user account address, if it is set to "", it will default to the current user address. + Endpoint string // Endpoint indicates the endpoint of sp. + SPAddress string // SPAddress indicates the HEX-encoded string of the sp address to be challenged. } func (o *GetObjectOptions) SetRange(start, end int64) error { @@ -296,44 +298,40 @@ func (o *GetObjectOptions) SetRange(start, end int64) error { return nil } +// EndPointOptions contains the options for querying a specified SP. type EndPointOptions struct { - Endpoint string // indicates the endpoint of sp - SPAddress string // indicates the HEX-encoded string of the sp address to be challenged + Endpoint string // Endpoint indicates the endpoint of sp. + SPAddress string // SPAddress indicates the HEX-encoded string of the sp address to be challenged. } +// ListBucketsOptions contains the options for `ListBuckets` API. type ListBucketsOptions struct { - // ShowRemovedObject determines whether to include buckets that have been marked as removed in the list. - // If set to false, these buckets will be skipped. - ShowRemovedBucket bool - - // Account defines the user account address - // if account is set to "", it will default to current user address - Account string - - Endpoint string // indicates the endpoint of sp - SPAddress string // indicates the HEX-encoded string of the sp address to be challenged + ShowRemovedBucket bool // ShowRemovedBucket determines whether to include buckets that have been marked as removed in the list. If set to false, these buckets will be skipped. + Account string // Account defines the user account address, if it is set to "", it will default to the current user address. + Endpoint string // Endpoint indicates the endpoint of sp. + SPAddress string // SPAddress indicates the HEX-encoded string of the sp address to be challenged. } +// ListBucketsByPaymentAccountOptions contains the options for `ListBucketsByPaymentAccount` API. type ListBucketsByPaymentAccountOptions struct { - Endpoint string // indicates the endpoint of sp - SPAddress string // indicates the HEX-encoded string of the sp address to be challenged + Endpoint string // Endpoint indicates the endpoint of sp. + SPAddress string // SPAddress indicates the HEX-encoded string of the sp address to be challenged. } +// ListUserPaymentAccountsOptions contains the options for `ListUserPaymentAccounts` API. type ListUserPaymentAccountsOptions struct { - // Account defines the user account address - // if account is set to "", it will default to current user address - Account string - Endpoint string // indicates the endpoint of sp - SPAddress string // indicates the HEX-encoded string of the sp address to be challenged + Account string // Account defines the user account address, if it is set to "", it will default to the current user address. + Endpoint string // Endpoint indicates the endpoint of sp. + SPAddress string // SPAddress indicates the HEX-encoded string of the sp address to be challenged. } +// ListObjectPoliciesOptions contains the options for `ListObjectPolicies` API. type ListObjectPoliciesOptions struct { // Limit determines the number of policies data records to be returned. // If the limit is set to 0, it will default to 50. // If the limit exceeds 1000, only 1000 records will be returned. - Limit int64 - // StartAfter is used to input the policy id for pagination purposes - StartAfter string - Endpoint string // indicates the endpoint of sp - SPAddress string // indicates the HEX-encoded string of the sp address to be challenged + Limit int64 + StartAfter string // StartAfter is used to input the policy id for pagination purposes. + Endpoint string // Endpoint indicates the endpoint of sp. + SPAddress string // SPAddress indicates the HEX-encoded string of the sp address to be challenged. } diff --git a/types/types.go b/types/types.go index 704bc225..2194e4b6 100644 --- a/types/types.go +++ b/types/types.go @@ -15,39 +15,38 @@ import ( var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") // Principal indicates the marshaled Principal content of greenfield permission types, -// user can generate it by NewPrincipalWithAccount or NewPrincipalWithGroupId method in utils +// user can generate it by NewPrincipalWithAccount or NewPrincipalWithGroupId method in utils. type Principal string -// ObjectStat contains the metadata of downloaded objects +// ObjectStat contains the metadata of the downloaded object. type ObjectStat struct { ObjectName string ContentType string Size int64 // Object size } -// ObjectInfo - +// ObjectDetail contains the detailed info of the object stored on Greenfield. type ObjectDetail struct { ObjectInfo *storagetypes.ObjectInfo GlobalVirtualGroup *types.GlobalVirtualGroup } -// QueryPieceInfo indicates the challenge or recovery object piece info -// RedundancyIndex if it is primary sp, the value should be -1, -// else it indicates the index of secondary sp +// QueryPieceInfo indicates the challenge or recovery object piece info. +// If it is primary sp, the RedundancyIndex value should be -1, else it indicates the index of secondary sp. type QueryPieceInfo struct { ObjectId string PieceIndex int RedundancyIndex int } -// ChallengeResult indicates the challenge hash and data results +// ChallengeResult includes the integrity hash, data results and hashes for storage provide to respond to challenges. type ChallengeResult struct { - PieceData io.ReadCloser - IntegrityHash string - PiecesHash []string + IntegrityHash string // the integrity hash of the challenged object + PieceData io.ReadCloser // the data of the segment/piece being challenged + PiecesHash []string // the hashes of the object's segments/pieces } +// RandStr - Generate a random string for test usage. func RandStr(n int) string { b := make([]rune, n) randMarker := rand.New(rand.NewSource(time.Now().UnixNano())) @@ -57,6 +56,7 @@ func RandStr(n int) string { return string(b) } +// StorageProvider indicates the metadata of SP that stored on-chain. type StorageProvider struct { Id uint32 OperatorAddress sdk.AccAddress From 76a33c87dad4bd3a51d88b089b1e8d61471d24f8 Mon Sep 17 00:00:00 2001 From: Alexxxxxx <118710506+alexgao001@users.noreply.github.com> Date: Thu, 21 Sep 2023 20:05:11 +0800 Subject: [PATCH 6/8] fix: validate basic before broadcasting tx (#182) * validateBasic before broadcast tx * add validation --- client/api_account.go | 8 ++++++++ client/api_basic.go | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/client/api_account.go b/client/api_account.go index 31aaac26..e34606eb 100644 --- a/client/api_account.go +++ b/client/api_account.go @@ -2,6 +2,7 @@ package client import ( "context" + "fmt" "cosmossdk.io/math" "github.com/bnb-chain/greenfield-go-sdk/types" @@ -299,6 +300,13 @@ func (c *Client) MultiTransfer(ctx context.Context, details []types.TransferDeta denom := gnfdSdkTypes.Denom sum := math.NewInt(0) for i := 0; i < len(details); i++ { + _, err := sdk.AccAddressFromHexUnsafe(details[i].ToAddress) + if err != nil { + return "", err + } + if details[i].Amount.IsNil() || details[i].Amount.IsNegative() { + return "", fmt.Errorf("transfer amount is not valid") + } outputs = append(outputs, bankTypes.Output{ Address: details[i].ToAddress, Coins: []sdk.Coin{{Denom: denom, Amount: details[i].Amount}}, diff --git a/client/api_basic.go b/client/api_basic.go index 11bde38e..fc5f1ca0 100644 --- a/client/api_basic.go +++ b/client/api_basic.go @@ -301,6 +301,14 @@ func (c *Client) WaitForTx(ctx context.Context, hash string) (*ctypes.ResultTx, // // - ret2: Return error when the request failed, otherwise return nil. func (c *Client) BroadcastTx(ctx context.Context, msgs []sdk.Msg, txOpt *types.TxOption, opts ...grpc.CallOption) (*tx.BroadcastTxResponse, error) { + if len(msgs) == 0 { + return nil, fmt.Errorf("msg is not provided in the transaction") + } + for _, msg := range msgs { + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + } resp, err := c.chainClient.BroadcastTx(ctx, msgs, txOpt, opts...) if err != nil { return nil, err From 141f5875281c00961aa739eb87ec829af042a848 Mon Sep 17 00:00:00 2001 From: flywukong <2229306838@qq.com> Date: Fri, 22 Sep 2023 10:36:51 +0800 Subject: [PATCH 7/8] fix: remove unuse option (#201) --- types/option.go | 1 - 1 file changed, 1 deletion(-) diff --git a/types/option.go b/types/option.go index 85a29e8d..8c506aed 100644 --- a/types/option.go +++ b/types/option.go @@ -220,7 +220,6 @@ type PutObjectOptions struct { // GetObjectOptions contains the options for `GetObject` API. type GetObjectOptions struct { Range string `url:"-" header:"Range,omitempty"` // Range support for downloading partial data. - SupportRecovery bool // SupportRecovery support recover data from secondary SPs if primary SP not in service. SupportResumable bool // SupportResumable support resumable download. Resumable downloads refer to the capability of resuming interrupted or incomplete downloads from the point where they were paused or disrupted. PartSize uint64 // PartSize indicate the resumable download's part size, download a large file in multiple parts. The part size is an integer multiple of the segment size. } From e3b88e9256baa304845f47c7d28426a56f6a9203 Mon Sep 17 00:00:00 2001 From: Alexxxxxx <118710506+alexgao001@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:07:22 +0800 Subject: [PATCH 8/8] bump versions (#199) --- .github/workflows/e2e.yml | 4 ++-- go.mod | 4 ++-- go.sum | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index b34217d0..b1c9b9c5 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -12,8 +12,8 @@ on: - develop env: - GreenfieldTag: v0.2.5 - GreenfieldStorageProviderTag: develop + GreenfieldTag: v0.2.6 + GreenfieldStorageProviderTag: v0.2.6 GOPRIVATE: github.com/bnb-chain GH_ACCESS_TOKEN: ${{ secrets.GH_TOKEN }} MYSQL_USER: root diff --git a/go.mod b/go.mod index bde20d39..3f47c372 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( cosmossdk.io/errors v1.0.0-beta.7 cosmossdk.io/math v1.0.1 - github.com/bnb-chain/greenfield v0.2.5 + github.com/bnb-chain/greenfield v0.2.6 github.com/bnb-chain/greenfield-common/go v0.0.0-20230830120314-a54ffd6da39f github.com/cometbft/cometbft v0.37.2 github.com/consensys/gnark-crypto v0.7.0 @@ -147,7 +147,7 @@ replace ( github.com/cometbft/cometbft => github.com/bnb-chain/greenfield-cometbft v0.0.3 github.com/cometbft/cometbft-db => github.com/bnb-chain/greenfield-cometbft-db v0.8.1-alpha.1 github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 - github.com/cosmos/cosmos-sdk => github.com/bnb-chain/greenfield-cosmos-sdk v0.2.5 + github.com/cosmos/cosmos-sdk => github.com/bnb-chain/greenfield-cosmos-sdk v0.2.6 github.com/cosmos/iavl => github.com/bnb-chain/greenfield-iavl v0.20.1 github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 ) diff --git a/go.sum b/go.sum index 192659d7..a2806fdf 100644 --- a/go.sum +++ b/go.sum @@ -152,16 +152,16 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= -github.com/bnb-chain/greenfield v0.2.5 h1:AmHvGfJmHm7FXB4II4mAB6i68bw98p86ZlIs9r6YeRM= -github.com/bnb-chain/greenfield v0.2.5/go.mod h1:nNsy8QGR8+R0j6Qz/duNE94NDDNuomC6wWDCzfl7jKc= +github.com/bnb-chain/greenfield v0.2.6 h1:U40wmSBQR4Wd0HiVCu/J6zqoLS4YUrvNgyuX71kgK3U= +github.com/bnb-chain/greenfield v0.2.6/go.mod h1:8kGVzKu3BEbpotk2Lmp/OzPh+nhbMsuUJueZtn0he4s= github.com/bnb-chain/greenfield-cometbft v0.0.3 h1:tv8NMy3bzX/1urqXGQIIAZSLy83loiI+dG0VKeyh1CY= github.com/bnb-chain/greenfield-cometbft v0.0.3/go.mod h1:f35mk/r5ab6yvzlqEWZt68LfUje68sYgMpVlt2CUYMk= github.com/bnb-chain/greenfield-cometbft-db v0.8.1-alpha.1 h1:XcWulGacHVRiSCx90Q8Y//ajOrLNBQWR/KDB89dy3cU= github.com/bnb-chain/greenfield-cometbft-db v0.8.1-alpha.1/go.mod h1:ey1CiK4bYo1RBNJLRiVbYr5CMdSxci9S/AZRINLtppI= github.com/bnb-chain/greenfield-common/go v0.0.0-20230830120314-a54ffd6da39f h1:zJvB2wCd80DQ9Nh/ZNQiP8MrHygSpDoav7OzHyIi/pM= github.com/bnb-chain/greenfield-common/go v0.0.0-20230830120314-a54ffd6da39f/go.mod h1:it3JJVHeG9Wp4QED2GkY/7V9Qo3BuPdoC5/4/U6ecJM= -github.com/bnb-chain/greenfield-cosmos-sdk v0.2.5 h1:8zIn/ExfMHZVBbVwhILG9KYO1m3pZO8I8stpqbFgzkk= -github.com/bnb-chain/greenfield-cosmos-sdk v0.2.5/go.mod h1:y3hDhQhil5hMIhwBTpu07RZBF30ZITkoE+GHhVZChtY= +github.com/bnb-chain/greenfield-cosmos-sdk v0.2.6 h1:aPrd2nG2nYZr8nSmGgN8efus6sni4OIZ1Bdx6s+mS3A= +github.com/bnb-chain/greenfield-cosmos-sdk v0.2.6/go.mod h1:y3hDhQhil5hMIhwBTpu07RZBF30ZITkoE+GHhVZChtY= github.com/bnb-chain/greenfield-cosmos-sdk/api v0.0.0-20230816082903-b48770f5e210 h1:GHPbV2bC+gmuO6/sG0Tm8oGal3KKSRlyE+zPscDjlA8= github.com/bnb-chain/greenfield-cosmos-sdk/api v0.0.0-20230816082903-b48770f5e210/go.mod h1:vhsZxXE9tYJeYB5JR4hPhd6Pc/uPf7j1T8IJ7p9FdeM= github.com/bnb-chain/greenfield-cosmos-sdk/math v0.0.0-20230816082903-b48770f5e210 h1:FLVOn4+OVbsKi2+YJX5kmD27/4dRu4FW7xCXFhzDO5s=